diff --git a/mover-restic/SOURCE_VERSIONS b/mover-restic/SOURCE_VERSIONS index 3d3b7dd0a..b86a53d0a 100644 --- a/mover-restic/SOURCE_VERSIONS +++ b/mover-restic/SOURCE_VERSIONS @@ -1,2 +1,2 @@ -https://github.com/restic/restic.git v0.17.1 975aa41e1e6a1c88deb501451f23cbdbb013f1da +https://github.com/restic/restic.git v0.17.0 277c8f5029a12bd882c2c1d2088f435caec67bb8 https://github.com/minio/minio-go.git v7.0.66 5415e6c72a71610108fe05ee747ac760dd40094f diff --git a/mover-restic/restic/.github/workflows/docker.yml b/mover-restic/restic/.github/workflows/docker.yml index a24660b45..a943d1b15 100644 --- a/mover-restic/restic/.github/workflows/docker.yml +++ b/mover-restic/restic/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@v4 - name: Log in to the Container registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 + uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} diff --git a/mover-restic/restic/.github/workflows/tests.yml b/mover-restic/restic/.github/workflows/tests.yml index 2ffeb5ff2..3ca7a9edb 100644 --- a/mover-restic/restic/.github/workflows/tests.yml +++ b/mover-restic/restic/.github/workflows/tests.yml @@ -66,9 +66,6 @@ jobs: GOPROXY: https://proxy.golang.org steps: - - name: Check out code - uses: actions/checkout@v4 - - name: Set up Go ${{ matrix.go }} uses: actions/setup-go@v5 with: @@ -142,6 +139,9 @@ jobs: echo $Env:USERPROFILE\tar\bin >> $Env:GITHUB_PATH if: matrix.os == 'windows-latest' + - name: Check out code + uses: actions/checkout@v4 + - name: Build with build.go run: | go run build.go @@ -230,14 +230,14 @@ jobs: name: Cross Compile for subset ${{ matrix.subset }} steps: - - name: Check out code - uses: actions/checkout@v4 - - name: Set up Go ${{ env.latest_go }} uses: actions/setup-go@v5 with: go-version: ${{ env.latest_go }} + - name: Check out code + uses: actions/checkout@v4 + - name: Cross-compile for subset ${{ matrix.subset }} run: | mkdir build-output build-output-debug @@ -252,14 +252,14 @@ jobs: # allow annotating code in the PR checks: write steps: - - name: Check out code - uses: actions/checkout@v4 - - name: Set up Go ${{ env.latest_go }} uses: actions/setup-go@v5 with: go-version: ${{ env.latest_go }} + - name: Check out code + uses: actions/checkout@v4 + - name: golangci-lint uses: golangci/golangci-lint-action@v6 with: diff --git a/mover-restic/restic/CHANGELOG.md b/mover-restic/restic/CHANGELOG.md index 9a5393915..2a6926755 100644 --- a/mover-restic/restic/CHANGELOG.md +++ b/mover-restic/restic/CHANGELOG.md @@ -1,6 +1,5 @@ # Table of Contents -* [Changelog for 0.17.1](#changelog-for-restic-0171-2024-09-05) * [Changelog for 0.17.0](#changelog-for-restic-0170-2024-07-26) * [Changelog for 0.16.5](#changelog-for-restic-0165-2024-07-01) * [Changelog for 0.16.4](#changelog-for-restic-0164-2024-02-04) @@ -36,230 +35,6 @@ * [Changelog for 0.6.0](#changelog-for-restic-060-2017-05-29) -# Changelog for restic 0.17.1 (2024-09-05) -The following sections list the changes in restic 0.17.1 relevant to -restic users. The changes are ordered by importance. - -## Summary - - * Fix #2004: Correctly handle volume names in `backup` command on Windows - * Fix #4945: Include missing backup error text with `--json` - * Fix #4953: Correctly handle long paths on older Windows versions - * Fix #4957: Fix delayed cancellation of certain commands - * Fix #4958: Don't ignore metadata-setting errors during restore - * Fix #4969: Correctly restore timestamp for files with resource forks on macOS - * Fix #4975: Prevent `backup --stdin-from-command` from panicking - * Fix #4980: Skip extended attribute processing on unsupported Windows volumes - * Fix #5004: Fix spurious "A Required Privilege Is Not Held by the Client" error - * Fix #5005: Fix rare failures to retry locking a repository - * Fix #5018: Improve HTTP/2 support for REST backend - * Chg #4953: Also back up files with incomplete metadata - * Enh #4795: Display progress bar for `restore --verify` - * Enh #4934: Automatically clear removed snapshots from cache - * Enh #4944: Print JSON-formatted errors during `restore --json` - * Enh #4959: Return exit code 12 for "bad password" errors - * Enh #4970: Make timeout for stuck requests customizable - -## Details - - * Bugfix #2004: Correctly handle volume names in `backup` command on Windows - - On Windows, when the specified backup target only included the volume name - without a trailing slash, for example, `C:`, then restoring the resulting - snapshot would result in an error. Note that using `C:\` as backup target worked - correctly. - - Specifying volume names is now handled correctly. To restore snapshots created - before this bugfix, use the : syntax. For example, to restore - a snapshot with ID `12345678` that backed up `C:`, use the following command: - - ``` - restic restore 12345678:/C/C:./ --target output/folder - ``` - - https://github.com/restic/restic/issues/2004 - https://github.com/restic/restic/pull/5028 - - * Bugfix #4945: Include missing backup error text with `--json` - - Previously, when running a backup with the `--json` option, restic failed to - include the actual error message in the output, resulting in `"error": {}` being - displayed. - - This has now been fixed, and restic now includes the error text in JSON output. - - https://github.com/restic/restic/issues/4945 - https://github.com/restic/restic/pull/4946 - - * Bugfix #4953: Correctly handle long paths on older Windows versions - - On older Windows versions, like Windows Server 2012, restic 0.17.0 failed to - back up files with long paths. This problem has now been resolved. - - https://github.com/restic/restic/issues/4953 - https://github.com/restic/restic/pull/4954 - - * Bugfix #4957: Fix delayed cancellation of certain commands - - Since restic 0.17.0, some commands did not immediately respond to cancellation - via Ctrl-C (SIGINT) and continued running for a short period. The most affected - commands were `diff`,`find`, `ls`, `stats` and `rewrite`. This is now resolved. - - https://github.com/restic/restic/issues/4957 - https://github.com/restic/restic/pull/4960 - - * Bugfix #4958: Don't ignore metadata-setting errors during restore - - Previously, restic used to ignore errors when setting timestamps, attributes, or - file modes during a restore. It now reports those errors, except for permission - related errors when running without root privileges. - - https://github.com/restic/restic/pull/4958 - - * Bugfix #4969: Correctly restore timestamp for files with resource forks on macOS - - On macOS, timestamps were not restored for files with resource forks. This has - now been fixed. - - https://github.com/restic/restic/issues/4969 - https://github.com/restic/restic/pull/5006 - - * Bugfix #4975: Prevent `backup --stdin-from-command` from panicking - - Restic would previously crash if `--stdin-from-command` was specified without - providing a command. This issue has now been fixed. - - https://github.com/restic/restic/issues/4975 - https://github.com/restic/restic/pull/4976 - - * Bugfix #4980: Skip extended attribute processing on unsupported Windows volumes - - With restic 0.17.0, backups of certain Windows paths, such as network drives, - failed due to errors while fetching extended attributes. - - Restic now skips extended attribute processing for volumes where they are not - supported. - - https://github.com/restic/restic/issues/4955 - https://github.com/restic/restic/issues/4950 - https://github.com/restic/restic/pull/4980 - https://github.com/restic/restic/pull/4998 - - * Bugfix #5004: Fix spurious "A Required Privilege Is Not Held by the Client" error - - On Windows, creating a backup could sometimes trigger the following error: - - ``` - error: nodeFromFileInfo [...]: get named security info failed with: a required privilege is not held by the client. - ``` - - This has now been fixed. - - https://github.com/restic/restic/issues/5004 - https://github.com/restic/restic/pull/5019 - - * Bugfix #5005: Fix rare failures to retry locking a repository - - Restic 0.17.0 could in rare cases fail to retry locking a repository if one of - the lock files failed to load, resulting in the error: - - ``` - unable to create lock in backend: circuit breaker open for file - ``` - - This issue has now been addressed. The error handling now properly retries the - locking operation. In addition, restic waits a few seconds between locking - retries to increase chances of successful locking. - - https://github.com/restic/restic/issues/5005 - https://github.com/restic/restic/pull/5011 - https://github.com/restic/restic/pull/5012 - - * Bugfix #5018: Improve HTTP/2 support for REST backend - - If `rest-server` tried to gracefully shut down an HTTP/2 connection still in use - by the client, it could result in the following error: - - ``` - http2: Transport: cannot retry err [http2: Transport received Server's graceful shutdown GOAWAY] after Request.Body was written; define Request.GetBody to avoid this error - ``` - - This issue has now been resolved. - - https://github.com/restic/restic/pull/5018 - https://forum.restic.net/t/receiving-http2-goaway-messages-with-windows-restic-v0-17-0/8367 - - * Change #4953: Also back up files with incomplete metadata - - If restic failed to read extended metadata for a file or folder during a backup, - then the file or folder was not included in the resulting snapshot. Instead, a - warning message was printed along with returning exit code 3 once the backup was - finished. - - Now, restic also includes items for which the extended metadata could not be - read in a snapshot. The warning message has been updated to: - - ``` - incomplete metadata for /path/to/file:
- ``` - - https://github.com/restic/restic/issues/4953 - https://github.com/restic/restic/pull/4977 - - * Enhancement #4795: Display progress bar for `restore --verify` - - When the `restore` command is run with `--verify`, it now displays a progress - bar while the verification step is running. The progress bar is not shown when - the `--json` flag is specified. - - https://github.com/restic/restic/issues/4795 - https://github.com/restic/restic/pull/4989 - - * Enhancement #4934: Automatically clear removed snapshots from cache - - Previously, restic only removed snapshots from the cache on the host where the - `forget` command was executed. On other hosts that use the same repository, the - old snapshots remained in the cache. - - Restic now automatically clears old snapshots from the local cache of the - current host. - - https://github.com/restic/restic/issues/4934 - https://github.com/restic/restic/pull/4981 - - * Enhancement #4944: Print JSON-formatted errors during `restore --json` - - Restic used to print any `restore` errors directly to the console as freeform - text messages, even when using the `--json` option. - - Now, when `--json` is specified, restic prints them as JSON formatted messages. - - https://github.com/restic/restic/issues/4944 - https://github.com/restic/restic/pull/4946 - - * Enhancement #4959: Return exit code 12 for "bad password" errors - - Restic now returns exit code 12 when it cannot open the repository due to an - incorrect password. - - https://github.com/restic/restic/pull/4959 - - * Enhancement #4970: Make timeout for stuck requests customizable - - Restic monitors connections to the backend to detect stuck requests. If a - request does not return any data within five minutes, restic assumes the request - is stuck and retries it. However, for large repositories this timeout might be - insufficient to collect a list of all files, causing the following error: - - `List(data) returned error, retrying after 1s: [...]: request timeout` - - It is now possible to increase the timeout using the `--stuck-request-timeout` - option. - - https://github.com/restic/restic/issues/4970 - https://github.com/restic/restic/pull/5014 - - # Changelog for restic 0.17.0 (2024-07-26) The following sections list the changes in restic 0.17.0 relevant to restic users. The changes are ordered by importance. diff --git a/mover-restic/restic/VERSION b/mover-restic/restic/VERSION index 7cca7711a..c5523bd09 100644 --- a/mover-restic/restic/VERSION +++ b/mover-restic/restic/VERSION @@ -1 +1 @@ -0.17.1 +0.17.0 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-2004 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-2004 deleted file mode 100644 index 5372eeb8c..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-2004 +++ /dev/null @@ -1,18 +0,0 @@ -Bugfix: Correctly handle volume names in `backup` command on Windows - -On Windows, when the specified backup target only included the volume -name without a trailing slash, for example, `C:`, then restoring the -resulting snapshot would result in an error. Note that using `C:\` -as backup target worked correctly. - -Specifying volume names is now handled correctly. To restore snapshots -created before this bugfix, use the : syntax. For -example, to restore a snapshot with ID `12345678` that backed up `C:`, -use the following command: - -``` -restic restore 12345678:/C/C:./ --target output/folder -``` - -https://github.com/restic/restic/issues/2004 -https://github.com/restic/restic/pull/5028 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4795 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4795 deleted file mode 100644 index ff86f0931..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4795 +++ /dev/null @@ -1,8 +0,0 @@ -Enhancement: Display progress bar for `restore --verify` - -When the `restore` command is run with `--verify`, it now displays a progress -bar while the verification step is running. The progress bar is not shown when -the `--json` flag is specified. - -https://github.com/restic/restic/issues/4795 -https://github.com/restic/restic/pull/4989 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4934 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4934 deleted file mode 100644 index df77109a7..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4934 +++ /dev/null @@ -1,11 +0,0 @@ -Enhancement: Automatically clear removed snapshots from cache - -Previously, restic only removed snapshots from the cache on the host where the -`forget` command was executed. On other hosts that use the same repository, the -old snapshots remained in the cache. - -Restic now automatically clears old snapshots from the local cache of the -current host. - -https://github.com/restic/restic/issues/4934 -https://github.com/restic/restic/pull/4981 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4944 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4944 deleted file mode 100644 index 95ae24c03..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4944 +++ /dev/null @@ -1,9 +0,0 @@ -Enhancement: Print JSON-formatted errors during `restore --json` - -Restic used to print any `restore` errors directly to the console as freeform -text messages, even when using the `--json` option. - -Now, when `--json` is specified, restic prints them as JSON formatted messages. - -https://github.com/restic/restic/issues/4944 -https://github.com/restic/restic/pull/4946 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4945 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4945 deleted file mode 100644 index a7a483fed..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4945 +++ /dev/null @@ -1,10 +0,0 @@ -Bugfix: Include missing backup error text with `--json` - -Previously, when running a backup with the `--json` option, restic failed to -include the actual error message in the output, resulting in `"error": {}` -being displayed. - -This has now been fixed, and restic now includes the error text in JSON output. - -https://github.com/restic/restic/issues/4945 -https://github.com/restic/restic/pull/4946 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4953 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4953 deleted file mode 100644 index c542377fc..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4953 +++ /dev/null @@ -1,7 +0,0 @@ -Bugfix: Correctly handle long paths on older Windows versions - -On older Windows versions, like Windows Server 2012, restic 0.17.0 failed to -back up files with long paths. This problem has now been resolved. - -https://github.com/restic/restic/issues/4953 -https://github.com/restic/restic/pull/4954 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4957 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4957 deleted file mode 100644 index 59c73b5c7..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4957 +++ /dev/null @@ -1,8 +0,0 @@ -Bugfix: Fix delayed cancellation of certain commands - -Since restic 0.17.0, some commands did not immediately respond to cancellation -via Ctrl-C (SIGINT) and continued running for a short period. The most affected -commands were `diff`,`find`, `ls`, `stats` and `rewrite`. This is now resolved. - -https://github.com/restic/restic/issues/4957 -https://github.com/restic/restic/pull/4960 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4969 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4969 deleted file mode 100644 index d92392a20..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4969 +++ /dev/null @@ -1,7 +0,0 @@ -Bugfix: Correctly restore timestamp for files with resource forks on macOS - -On macOS, timestamps were not restored for files with resource forks. This has -now been fixed. - -https://github.com/restic/restic/issues/4969 -https://github.com/restic/restic/pull/5006 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4970 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4970 deleted file mode 100644 index 422ae3c25..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4970 +++ /dev/null @@ -1,15 +0,0 @@ -Enhancement: Make timeout for stuck requests customizable - -Restic monitors connections to the backend to detect stuck requests. If a -request does not return any data within five minutes, restic assumes the -request is stuck and retries it. However, for large repositories this timeout -might be insufficient to collect a list of all files, causing the following -error: - -`List(data) returned error, retrying after 1s: [...]: request timeout` - -It is now possible to increase the timeout using the `--stuck-request-timeout` -option. - -https://github.com/restic/restic/issues/4970 -https://github.com/restic/restic/pull/5014 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4975 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4975 deleted file mode 100644 index 614642c06..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-4975 +++ /dev/null @@ -1,7 +0,0 @@ -Bugfix: Prevent `backup --stdin-from-command` from panicking - -Restic would previously crash if `--stdin-from-command` was specified without -providing a command. This issue has now been fixed. - -https://github.com/restic/restic/issues/4975 -https://github.com/restic/restic/pull/4976 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-5004 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-5004 deleted file mode 100644 index 72e98a9a4..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-5004 +++ /dev/null @@ -1,12 +0,0 @@ -Bugfix: Fix spurious "A Required Privilege Is Not Held by the Client" error - -On Windows, creating a backup could sometimes trigger the following error: - -``` -error: nodeFromFileInfo [...]: get named security info failed with: a required privilege is not held by the client. -``` - -This has now been fixed. - -https://github.com/restic/restic/issues/5004 -https://github.com/restic/restic/pull/5019 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-5005 b/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-5005 deleted file mode 100644 index 16ac83b4a..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/issue-5005 +++ /dev/null @@ -1,16 +0,0 @@ -Bugfix: Fix rare failures to retry locking a repository - -Restic 0.17.0 could in rare cases fail to retry locking a repository if one of -the lock files failed to load, resulting in the error: - -``` -unable to create lock in backend: circuit breaker open for file -``` - -This issue has now been addressed. The error handling now properly retries the -locking operation. In addition, restic waits a few seconds between locking -retries to increase chances of successful locking. - -https://github.com/restic/restic/issues/5005 -https://github.com/restic/restic/pull/5011 -https://github.com/restic/restic/pull/5012 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4958 b/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4958 deleted file mode 100644 index dae9b2c8e..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4958 +++ /dev/null @@ -1,7 +0,0 @@ -Bugfix: Don't ignore metadata-setting errors during restore - -Previously, restic used to ignore errors when setting timestamps, attributes, -or file modes during a restore. It now reports those errors, except for -permission related errors when running without root privileges. - -https://github.com/restic/restic/pull/4958 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4959 b/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4959 deleted file mode 100644 index 80b2780b2..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4959 +++ /dev/null @@ -1,6 +0,0 @@ -Enhancement: Return exit code 12 for "bad password" errors - -Restic now returns exit code 12 when it cannot open the repository due to an -incorrect password. - -https://github.com/restic/restic/pull/4959 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4977 b/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4977 deleted file mode 100644 index 781576a56..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4977 +++ /dev/null @@ -1,16 +0,0 @@ -Change: Also back up files with incomplete metadata - -If restic failed to read extended metadata for a file or folder during a -backup, then the file or folder was not included in the resulting snapshot. -Instead, a warning message was printed along with returning exit code 3 once -the backup was finished. - -Now, restic also includes items for which the extended metadata could not be -read in a snapshot. The warning message has been updated to: - -``` -incomplete metadata for /path/to/file:
-``` - -https://github.com/restic/restic/issues/4953 -https://github.com/restic/restic/pull/4977 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4980 b/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4980 deleted file mode 100644 index b51ee8d59..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-4980 +++ /dev/null @@ -1,12 +0,0 @@ -Bugfix: Skip extended attribute processing on unsupported Windows volumes - -With restic 0.17.0, backups of certain Windows paths, such as network drives, -failed due to errors while fetching extended attributes. - -Restic now skips extended attribute processing for volumes where they are not -supported. - -https://github.com/restic/restic/pull/4980 -https://github.com/restic/restic/pull/4998 -https://github.com/restic/restic/issues/4955 -https://github.com/restic/restic/issues/4950 diff --git a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-5018 b/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-5018 deleted file mode 100644 index ca600c3e1..000000000 --- a/mover-restic/restic/changelog/0.17.1_2024-09-05/pull-5018 +++ /dev/null @@ -1,13 +0,0 @@ -Bugfix: Improve HTTP/2 support for REST backend - -If `rest-server` tried to gracefully shut down an HTTP/2 connection still in -use by the client, it could result in the following error: - -``` -http2: Transport: cannot retry err [http2: Transport received Server's graceful shutdown GOAWAY] after Request.Body was written; define Request.GetBody to avoid this error -``` - -This issue has now been resolved. - -https://github.com/restic/restic/pull/5018 -https://forum.restic.net/t/receiving-http2-goaway-messages-with-windows-restic-v0-17-0/8367 diff --git a/mover-restic/restic/cmd/restic/cmd_backup.go b/mover-restic/restic/cmd/restic/cmd_backup.go index 562108a33..9957b5784 100644 --- a/mover-restic/restic/cmd/restic/cmd_backup.go +++ b/mover-restic/restic/cmd/restic/cmd_backup.go @@ -43,7 +43,6 @@ Exit status is 1 if there was a fatal error (no snapshot created). Exit status is 3 if some source data could not be read (incomplete snapshot created). Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, PreRun: func(_ *cobra.Command, _ []string) { if backupOptions.Host == "" { @@ -55,7 +54,6 @@ Exit status is 12 if the password is incorrect. backupOptions.Host = hostname } }, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { term, cancel := setupTermstatus() diff --git a/mover-restic/restic/cmd/restic/cmd_cache.go b/mover-restic/restic/cmd/restic/cmd_cache.go index e54c73451..e71d38365 100644 --- a/mover-restic/restic/cmd/restic/cmd_cache.go +++ b/mover-restic/restic/cmd/restic/cmd_cache.go @@ -28,7 +28,6 @@ EXIT STATUS Exit status is 0 if the command was successful. Exit status is 1 if there was any error. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(_ *cobra.Command, args []string) error { return runCache(cacheOptions, globalOptions, args) diff --git a/mover-restic/restic/cmd/restic/cmd_cat.go b/mover-restic/restic/cmd/restic/cmd_cat.go index 6160c54df..693c26790 100644 --- a/mover-restic/restic/cmd/restic/cmd_cat.go +++ b/mover-restic/restic/cmd/restic/cmd_cat.go @@ -12,8 +12,6 @@ import ( "github.com/restic/restic/internal/restic" ) -var catAllowedCmds = []string{"config", "index", "snapshot", "key", "masterkey", "lock", "pack", "blob", "tree"} - var cmdCat = &cobra.Command{ Use: "cat [flags] [masterkey|config|pack ID|blob ID|snapshot ID|index ID|key ID|lock ID|tree snapshot:subfolder]", Short: "Print internal objects to stdout", @@ -27,14 +25,11 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runCat(cmd.Context(), globalOptions, args) }, - ValidArgs: catAllowedCmds, } func init() { @@ -42,19 +37,21 @@ func init() { } func validateCatArgs(args []string) error { + var allowedCmds = []string{"config", "index", "snapshot", "key", "masterkey", "lock", "pack", "blob", "tree"} + if len(args) < 1 { return errors.Fatal("type not specified") } validType := false - for _, v := range catAllowedCmds { + for _, v := range allowedCmds { if v == args[0] { validType = true break } } if !validType { - return errors.Fatalf("invalid type %q, must be one of [%s]", args[0], strings.Join(catAllowedCmds, "|")) + return errors.Fatalf("invalid type %q, must be one of [%s]", args[0], strings.Join(allowedCmds, "|")) } if args[0] != "masterkey" && args[0] != "config" && len(args) != 2 { diff --git a/mover-restic/restic/cmd/restic/cmd_check.go b/mover-restic/restic/cmd/restic/cmd_check.go index dcf7f27df..9cccc0609 100644 --- a/mover-restic/restic/cmd/restic/cmd_check.go +++ b/mover-restic/restic/cmd/restic/cmd_check.go @@ -39,9 +39,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { term, cancel := setupTermstatus() diff --git a/mover-restic/restic/cmd/restic/cmd_copy.go b/mover-restic/restic/cmd/restic/cmd_copy.go index cd92193ac..d7761174a 100644 --- a/mover-restic/restic/cmd/restic/cmd_copy.go +++ b/mover-restic/restic/cmd/restic/cmd_copy.go @@ -38,10 +38,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, - DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runCopy(cmd.Context(), copyOptions, globalOptions, args) }, diff --git a/mover-restic/restic/cmd/restic/cmd_debug.go b/mover-restic/restic/cmd/restic/cmd_debug.go index b92192492..74c21df24 100644 --- a/mover-restic/restic/cmd/restic/cmd_debug.go +++ b/mover-restic/restic/cmd/restic/cmd_debug.go @@ -29,10 +29,8 @@ import ( ) var cmdDebug = &cobra.Command{ - Use: "debug", - Short: "Debug commands", - GroupID: cmdGroupDefault, - DisableAutoGenTag: true, + Use: "debug", + Short: "Debug commands", } var cmdDebugDump = &cobra.Command{ @@ -49,7 +47,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_diff.go b/mover-restic/restic/cmd/restic/cmd_diff.go index 594e387e8..6488a7c35 100644 --- a/mover-restic/restic/cmd/restic/cmd_diff.go +++ b/mover-restic/restic/cmd/restic/cmd_diff.go @@ -43,9 +43,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runDiff(cmd.Context(), diffOptions, globalOptions, args) @@ -179,10 +177,6 @@ func (c *Comparer) printDir(ctx context.Context, mode string, stats *DiffStat, b } for _, node := range tree.Nodes { - if ctx.Err() != nil { - return ctx.Err() - } - name := path.Join(prefix, node.Name) if node.Type == "dir" { name += "/" @@ -193,13 +187,13 @@ func (c *Comparer) printDir(ctx context.Context, mode string, stats *DiffStat, b if node.Type == "dir" { err := c.printDir(ctx, mode, stats, blobs, name, *node.Subtree) - if err != nil && err != context.Canceled { + if err != nil { Warnf("error: %v\n", err) } } } - return ctx.Err() + return nil } func (c *Comparer) collectDir(ctx context.Context, blobs restic.BlobSet, id restic.ID) error { @@ -210,21 +204,17 @@ func (c *Comparer) collectDir(ctx context.Context, blobs restic.BlobSet, id rest } for _, node := range tree.Nodes { - if ctx.Err() != nil { - return ctx.Err() - } - addBlobs(blobs, node) if node.Type == "dir" { err := c.collectDir(ctx, blobs, *node.Subtree) - if err != nil && err != context.Canceled { + if err != nil { Warnf("error: %v\n", err) } } } - return ctx.Err() + return nil } func uniqueNodeNames(tree1, tree2 *restic.Tree) (tree1Nodes, tree2Nodes map[string]*restic.Node, uniqueNames []string) { @@ -265,10 +255,6 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref tree1Nodes, tree2Nodes, names := uniqueNodeNames(tree1, tree2) for _, name := range names { - if ctx.Err() != nil { - return ctx.Err() - } - node1, t1 := tree1Nodes[name] node2, t2 := tree2Nodes[name] @@ -318,7 +304,7 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref } else { err = c.diffTree(ctx, stats, name, *node1.Subtree, *node2.Subtree) } - if err != nil && err != context.Canceled { + if err != nil { Warnf("error: %v\n", err) } } @@ -332,7 +318,7 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref if node1.Type == "dir" { err := c.printDir(ctx, "-", &stats.Removed, stats.BlobsBefore, prefix, *node1.Subtree) - if err != nil && err != context.Canceled { + if err != nil { Warnf("error: %v\n", err) } } @@ -346,14 +332,14 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref if node2.Type == "dir" { err := c.printDir(ctx, "+", &stats.Added, stats.BlobsAfter, prefix, *node2.Subtree) - if err != nil && err != context.Canceled { + if err != nil { Warnf("error: %v\n", err) } } } } - return ctx.Err() + return nil } func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_dump.go b/mover-restic/restic/cmd/restic/cmd_dump.go index 7d6652e17..7e1efa3ae 100644 --- a/mover-restic/restic/cmd/restic/cmd_dump.go +++ b/mover-restic/restic/cmd/restic/cmd_dump.go @@ -38,9 +38,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runDump(cmd.Context(), dumpOptions, globalOptions, args) @@ -87,10 +85,6 @@ func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.BlobLoade item := filepath.Join(prefix, pathComponents[0]) l := len(pathComponents) for _, node := range tree.Nodes { - if ctx.Err() != nil { - return ctx.Err() - } - // If dumping something in the highest level it will just take the // first item it finds and dump that according to the switch case below. if node.Name == pathComponents[0] { diff --git a/mover-restic/restic/cmd/restic/cmd_features.go b/mover-restic/restic/cmd/restic/cmd_features.go index a2f04be31..497013696 100644 --- a/mover-restic/restic/cmd/restic/cmd_features.go +++ b/mover-restic/restic/cmd/restic/cmd_features.go @@ -31,7 +31,7 @@ EXIT STATUS Exit status is 0 if the command was successful. Exit status is 1 if there was any error. `, - GroupID: cmdGroupAdvanced, + Hidden: true, DisableAutoGenTag: true, RunE: func(_ *cobra.Command, args []string) error { if len(args) != 0 { diff --git a/mover-restic/restic/cmd/restic/cmd_find.go b/mover-restic/restic/cmd/restic/cmd_find.go index cb5c0e5e0..4f9549ca4 100644 --- a/mover-restic/restic/cmd/restic/cmd_find.go +++ b/mover-restic/restic/cmd/restic/cmd_find.go @@ -37,9 +37,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runFind(cmd.Context(), findOptions, globalOptions, args) @@ -379,10 +377,6 @@ func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error { if node.Type == "file" && f.blobIDs != nil { for _, id := range node.Content { - if ctx.Err() != nil { - return ctx.Err() - } - idStr := id.String() if _, ok := f.blobIDs[idStr]; !ok { // Look for short ID form diff --git a/mover-restic/restic/cmd/restic/cmd_forget.go b/mover-restic/restic/cmd/restic/cmd_forget.go index 58a9d25b7..87738b518 100644 --- a/mover-restic/restic/cmd/restic/cmd_forget.go +++ b/mover-restic/restic/cmd/restic/cmd_forget.go @@ -39,9 +39,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { term, cancel := setupTermstatus() @@ -248,10 +246,6 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption printer.P("Applying Policy: %v\n", policy) for k, snapshotGroup := range snapshotGroups { - if ctx.Err() != nil { - return ctx.Err() - } - if gopts.Verbose >= 1 && !gopts.JSON { err = PrintSnapshotGroupHeader(globalOptions.stdout, k) if err != nil { diff --git a/mover-restic/restic/cmd/restic/cmd_init.go b/mover-restic/restic/cmd/restic/cmd_init.go index 2a2aae1dc..3c0319e55 100644 --- a/mover-restic/restic/cmd/restic/cmd_init.go +++ b/mover-restic/restic/cmd/restic/cmd_init.go @@ -26,7 +26,6 @@ EXIT STATUS Exit status is 0 if the command was successful. Exit status is 1 if there was any error. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runInit(cmd.Context(), initOptions, globalOptions, args) diff --git a/mover-restic/restic/cmd/restic/cmd_init_integration_test.go b/mover-restic/restic/cmd/restic/cmd_init_integration_test.go index 4795d5510..9b5eed6e0 100644 --- a/mover-restic/restic/cmd/restic/cmd_init_integration_test.go +++ b/mover-restic/restic/cmd/restic/cmd_init_integration_test.go @@ -2,8 +2,6 @@ package main import ( "context" - "os" - "path/filepath" "testing" "github.com/restic/restic/internal/repository" @@ -18,11 +16,6 @@ func testRunInit(t testing.TB, opts GlobalOptions) { rtest.OK(t, runInit(context.TODO(), InitOptions{}, opts, nil)) t.Logf("repository initialized at %v", opts.Repo) - - // create temporary junk files to verify that restic does not trip over them - for _, path := range []string{"index", "snapshots", "keys", "locks", filepath.Join("data", "00")} { - rtest.OK(t, os.WriteFile(filepath.Join(opts.Repo, path, "tmp12345"), []byte("junk file"), 0o600)) - } } func TestInitCopyChunkerParams(t *testing.T) { diff --git a/mover-restic/restic/cmd/restic/cmd_key.go b/mover-restic/restic/cmd/restic/cmd_key.go index a94caa0d8..c687eca53 100644 --- a/mover-restic/restic/cmd/restic/cmd_key.go +++ b/mover-restic/restic/cmd/restic/cmd_key.go @@ -11,8 +11,6 @@ var cmdKey = &cobra.Command{ The "key" command allows you to set multiple access keys or passwords per repository. `, - DisableAutoGenTag: true, - GroupID: cmdGroupDefault, } func init() { diff --git a/mover-restic/restic/cmd/restic/cmd_key_add.go b/mover-restic/restic/cmd/restic/cmd_key_add.go index 2737410a0..c9f0ef233 100644 --- a/mover-restic/restic/cmd/restic/cmd_key_add.go +++ b/mover-restic/restic/cmd/restic/cmd_key_add.go @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, } diff --git a/mover-restic/restic/cmd/restic/cmd_key_list.go b/mover-restic/restic/cmd/restic/cmd_key_list.go index 1c70cce8a..ae751a487 100644 --- a/mover-restic/restic/cmd/restic/cmd_key_list.go +++ b/mover-restic/restic/cmd/restic/cmd_key_list.go @@ -27,7 +27,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_key_passwd.go b/mover-restic/restic/cmd/restic/cmd_key_passwd.go index 9bb141749..723acaaab 100644 --- a/mover-restic/restic/cmd/restic/cmd_key_passwd.go +++ b/mover-restic/restic/cmd/restic/cmd_key_passwd.go @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, } diff --git a/mover-restic/restic/cmd/restic/cmd_key_remove.go b/mover-restic/restic/cmd/restic/cmd_key_remove.go index 3cb2e0bd7..c4c24fdb7 100644 --- a/mover-restic/restic/cmd/restic/cmd_key_remove.go +++ b/mover-restic/restic/cmd/restic/cmd_key_remove.go @@ -24,7 +24,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_list.go b/mover-restic/restic/cmd/restic/cmd_list.go index 1a4791e31..060bca871 100644 --- a/mover-restic/restic/cmd/restic/cmd_list.go +++ b/mover-restic/restic/cmd/restic/cmd_list.go @@ -23,10 +23,8 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, - GroupID: cmdGroupDefault, RunE: func(cmd *cobra.Command, args []string) error { return runList(cmd.Context(), globalOptions, args) }, diff --git a/mover-restic/restic/cmd/restic/cmd_ls.go b/mover-restic/restic/cmd/restic/cmd_ls.go index 69e278103..76e192b6c 100644 --- a/mover-restic/restic/cmd/restic/cmd_ls.go +++ b/mover-restic/restic/cmd/restic/cmd_ls.go @@ -43,10 +43,8 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, - GroupID: cmdGroupDefault, RunE: func(cmd *cobra.Command, args []string) error { return runLs(cmd.Context(), lsOptions, globalOptions, args) }, diff --git a/mover-restic/restic/cmd/restic/cmd_migrate.go b/mover-restic/restic/cmd/restic/cmd_migrate.go index 5c3e425ed..e89980050 100644 --- a/mover-restic/restic/cmd/restic/cmd_migrate.go +++ b/mover-restic/restic/cmd/restic/cmd_migrate.go @@ -26,10 +26,8 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, - GroupID: cmdGroupDefault, RunE: func(cmd *cobra.Command, args []string) error { term, cancel := setupTermstatus() defer cancel() @@ -76,10 +74,8 @@ func checkMigrations(ctx context.Context, repo restic.Repository, printer progre func applyMigrations(ctx context.Context, opts MigrateOptions, gopts GlobalOptions, repo restic.Repository, args []string, term *termstatus.Terminal, printer progress.Printer) error { var firsterr error for _, name := range args { - found := false for _, m := range migrations.All { if m.Name() == name { - found = true ok, reason, err := m.Check(ctx, repo) if err != nil { return err @@ -123,9 +119,6 @@ func applyMigrations(ctx context.Context, opts MigrateOptions, gopts GlobalOptio printer.P("migration %v: success\n", m.Name()) } } - if !found { - printer.E("unknown migration %v", name) - } } return firsterr diff --git a/mover-restic/restic/cmd/restic/cmd_mount.go b/mover-restic/restic/cmd/restic/cmd_mount.go index 2f57a6d1f..3e0b159be 100644 --- a/mover-restic/restic/cmd/restic/cmd_mount.go +++ b/mover-restic/restic/cmd/restic/cmd_mount.go @@ -68,10 +68,8 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, - GroupID: cmdGroupDefault, RunE: func(cmd *cobra.Command, args []string) error { return runMount(cmd.Context(), mountOptions, globalOptions, args) }, diff --git a/mover-restic/restic/cmd/restic/cmd_mount_integration_test.go b/mover-restic/restic/cmd/restic/cmd_mount_integration_test.go index c5f4d193a..d764b4e4f 100644 --- a/mover-restic/restic/cmd/restic/cmd_mount_integration_test.go +++ b/mover-restic/restic/cmd/restic/cmd_mount_integration_test.go @@ -13,7 +13,6 @@ import ( "time" systemFuse "github.com/anacrolix/fuse" - "github.com/restic/restic/internal/debug" "github.com/restic/restic/internal/restic" rtest "github.com/restic/restic/internal/test" ) @@ -206,11 +205,6 @@ func TestMountSameTimestamps(t *testing.T) { t.Skip("Skipping fuse tests") } - debugEnabled := debug.TestLogToStderr(t) - if debugEnabled { - defer debug.TestDisableLog(t) - } - env, cleanup := withTestEnvironment(t) // must list snapshots more than once env.gopts.backendTestHook = nil diff --git a/mover-restic/restic/cmd/restic/cmd_options.go b/mover-restic/restic/cmd/restic/cmd_options.go index 9c07b2626..4cd574b68 100644 --- a/mover-restic/restic/cmd/restic/cmd_options.go +++ b/mover-restic/restic/cmd/restic/cmd_options.go @@ -20,7 +20,7 @@ EXIT STATUS Exit status is 0 if the command was successful. Exit status is 1 if there was any error. `, - GroupID: cmdGroupAdvanced, + Hidden: true, DisableAutoGenTag: true, Run: func(_ *cobra.Command, _ []string) { fmt.Printf("All Extended Options:\n") diff --git a/mover-restic/restic/cmd/restic/cmd_prune.go b/mover-restic/restic/cmd/restic/cmd_prune.go index e8473bd6f..7e706ccf8 100644 --- a/mover-restic/restic/cmd/restic/cmd_prune.go +++ b/mover-restic/restic/cmd/restic/cmd_prune.go @@ -32,9 +32,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { term, cancel := setupTermstatus() diff --git a/mover-restic/restic/cmd/restic/cmd_prune_integration_test.go b/mover-restic/restic/cmd/restic/cmd_prune_integration_test.go index 536ec40d8..746eb5cc9 100644 --- a/mover-restic/restic/cmd/restic/cmd_prune_integration_test.go +++ b/mover-restic/restic/cmd/restic/cmd_prune_integration_test.go @@ -146,9 +146,10 @@ func TestPruneWithDamagedRepository(t *testing.T) { env.gopts.backendTestHook = oldHook }() // prune should fail - rtest.Equals(t, repository.ErrPacksMissing, withTermStatus(env.gopts, func(ctx context.Context, term *termstatus.Terminal) error { + rtest.Assert(t, withTermStatus(env.gopts, func(ctx context.Context, term *termstatus.Terminal) error { return runPrune(context.TODO(), pruneDefaultOptions, env.gopts, term) - }), "prune should have reported index not complete error") + }) == repository.ErrPacksMissing, + "prune should have reported index not complete error") } // Test repos for edge cases diff --git a/mover-restic/restic/cmd/restic/cmd_recover.go b/mover-restic/restic/cmd/restic/cmd_recover.go index a6ef59cc2..5e4744bb6 100644 --- a/mover-restic/restic/cmd/restic/cmd_recover.go +++ b/mover-restic/restic/cmd/restic/cmd_recover.go @@ -26,9 +26,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { return runRecover(cmd.Context(), globalOptions) @@ -120,10 +118,6 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error { return nil } - if ctx.Err() != nil { - return ctx.Err() - } - tree := restic.NewTree(len(roots)) for id := range roots { var subtreeID = id diff --git a/mover-restic/restic/cmd/restic/cmd_repair.go b/mover-restic/restic/cmd/restic/cmd_repair.go index 6a1a1f9dc..aefe02f3c 100644 --- a/mover-restic/restic/cmd/restic/cmd_repair.go +++ b/mover-restic/restic/cmd/restic/cmd_repair.go @@ -5,10 +5,8 @@ import ( ) var cmdRepair = &cobra.Command{ - Use: "repair", - Short: "Repair the repository", - GroupID: cmdGroupDefault, - DisableAutoGenTag: true, + Use: "repair", + Short: "Repair the repository", } func init() { diff --git a/mover-restic/restic/cmd/restic/cmd_repair_index.go b/mover-restic/restic/cmd/restic/cmd_repair_index.go index 83c1bfa7f..e6b6e9fa5 100644 --- a/mover-restic/restic/cmd/restic/cmd_repair_index.go +++ b/mover-restic/restic/cmd/restic/cmd_repair_index.go @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_repair_packs.go b/mover-restic/restic/cmd/restic/cmd_repair_packs.go index 290c3734e..b0afefb2d 100644 --- a/mover-restic/restic/cmd/restic/cmd_repair_packs.go +++ b/mover-restic/restic/cmd/restic/cmd_repair_packs.go @@ -27,7 +27,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_repair_snapshots.go b/mover-restic/restic/cmd/restic/cmd_repair_snapshots.go index 385854312..fc221ebea 100644 --- a/mover-restic/restic/cmd/restic/cmd_repair_snapshots.go +++ b/mover-restic/restic/cmd/restic/cmd_repair_snapshots.go @@ -41,7 +41,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_restore.go b/mover-restic/restic/cmd/restic/cmd_restore.go index c58b0b80d..89942f4cf 100644 --- a/mover-restic/restic/cmd/restic/cmd_restore.go +++ b/mover-restic/restic/cmd/restic/cmd_restore.go @@ -36,9 +36,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { term, cancel := setupTermstatus() @@ -166,8 +164,9 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions, totalErrors := 0 res.Error = func(location string, err error) error { + msg.E("ignoring error for %s: %s\n", location, err) totalErrors++ - return progress.Error(location, err) + return nil } res.Warn = func(message string) { msg.E("Warning: %s\n", message) @@ -222,7 +221,7 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions, msg.P("restoring %s to %s\n", res.Snapshot(), opts.Target) } - countRestoredFiles, err := res.RestoreTo(ctx, opts.Target) + err = res.RestoreTo(ctx, opts.Target) if err != nil { return err } @@ -239,8 +238,7 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions, } var count int t0 := time.Now() - bar := newTerminalProgressMax(!gopts.Quiet && !gopts.JSON && stdoutIsTerminal(), 0, "files verified", term) - count, err = res.VerifyFiles(ctx, opts.Target, countRestoredFiles, bar) + count, err = res.VerifyFiles(ctx, opts.Target) if err != nil { return err } diff --git a/mover-restic/restic/cmd/restic/cmd_rewrite.go b/mover-restic/restic/cmd/restic/cmd_rewrite.go index 7788016b7..463720ee1 100644 --- a/mover-restic/restic/cmd/restic/cmd_rewrite.go +++ b/mover-restic/restic/cmd/restic/cmd_rewrite.go @@ -42,9 +42,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runRewrite(cmd.Context(), rewriteOptions, globalOptions, args) diff --git a/mover-restic/restic/cmd/restic/cmd_self_update.go b/mover-restic/restic/cmd/restic/cmd_self_update.go index 09c86bf2c..0fce41241 100644 --- a/mover-restic/restic/cmd/restic/cmd_self_update.go +++ b/mover-restic/restic/cmd/restic/cmd_self_update.go @@ -28,7 +28,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/mover-restic/restic/cmd/restic/cmd_snapshots.go b/mover-restic/restic/cmd/restic/cmd_snapshots.go index 42677918f..9112e1b95 100644 --- a/mover-restic/restic/cmd/restic/cmd_snapshots.go +++ b/mover-restic/restic/cmd/restic/cmd_snapshots.go @@ -27,9 +27,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runSnapshots(cmd.Context(), snapshotOptions, globalOptions, args) @@ -83,10 +81,6 @@ func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions } for k, list := range snapshotGroups { - if ctx.Err() != nil { - return ctx.Err() - } - if opts.Last { // This branch should be removed in the same time // that --last. @@ -107,10 +101,6 @@ func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions } for k, list := range snapshotGroups { - if ctx.Err() != nil { - return ctx.Err() - } - if grouped { err := PrintSnapshotGroupHeader(globalOptions.stdout, k) if err != nil { diff --git a/mover-restic/restic/cmd/restic/cmd_stats.go b/mover-restic/restic/cmd/restic/cmd_stats.go index 56cf213d1..ab333e6ef 100644 --- a/mover-restic/restic/cmd/restic/cmd_stats.go +++ b/mover-restic/restic/cmd/restic/cmd_stats.go @@ -53,9 +53,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runStats(cmd.Context(), statsOptions, globalOptions, args) @@ -72,20 +70,10 @@ type StatsOptions struct { var statsOptions StatsOptions -func must(err error) { - if err != nil { - panic(fmt.Sprintf("error during setup: %v", err)) - } -} - func init() { cmdRoot.AddCommand(cmdStats) f := cmdStats.Flags() f.StringVar(&statsOptions.countMode, "mode", countModeRestoreSize, "counting mode: restore-size (default), files-by-contents, blobs-per-file or raw-data") - must(cmdStats.RegisterFlagCompletionFunc("mode", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { - return []string{countModeRestoreSize, countModeUniqueFilesByContents, countModeBlobsPerFile, countModeRawData}, cobra.ShellCompDirectiveDefault - })) - initMultiSnapshotFilter(f, &statsOptions.SnapshotFilter, true) } diff --git a/mover-restic/restic/cmd/restic/cmd_tag.go b/mover-restic/restic/cmd/restic/cmd_tag.go index c7bf725e9..ea73955f0 100644 --- a/mover-restic/restic/cmd/restic/cmd_tag.go +++ b/mover-restic/restic/cmd/restic/cmd_tag.go @@ -29,9 +29,7 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { return runTag(cmd.Context(), tagOptions, globalOptions, args) diff --git a/mover-restic/restic/cmd/restic/cmd_unlock.go b/mover-restic/restic/cmd/restic/cmd_unlock.go index d87cde065..96eef7e02 100644 --- a/mover-restic/restic/cmd/restic/cmd_unlock.go +++ b/mover-restic/restic/cmd/restic/cmd_unlock.go @@ -19,7 +19,6 @@ EXIT STATUS Exit status is 0 if the command was successful. Exit status is 1 if there was any error. `, - GroupID: cmdGroupDefault, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { return runUnlock(cmd.Context(), unlockOptions, globalOptions) diff --git a/mover-restic/restic/cmd/restic/global.go b/mover-restic/restic/cmd/restic/global.go index 9df009d8c..080863da7 100644 --- a/mover-restic/restic/cmd/restic/global.go +++ b/mover-restic/restic/cmd/restic/global.go @@ -47,7 +47,7 @@ import ( // to a missing backend storage location or config file var ErrNoRepository = errors.New("repository does not exist") -var version = "0.17.1" +var version = "0.17.0" // TimeFormat is the format used for all timestamps printed by restic. const TimeFormat = "2006-01-02 15:04:05" @@ -140,7 +140,6 @@ func init() { f.UintVar(&globalOptions.PackSize, "pack-size", 0, "set target pack `size` in MiB, created pack files may be larger (default: $RESTIC_PACK_SIZE)") f.StringSliceVarP(&globalOptions.Options, "option", "o", []string{}, "set extended option (`key=value`, can be specified multiple times)") f.StringVar(&globalOptions.HTTPUserAgent, "http-user-agent", "", "set a http user agent for outgoing http requests") - f.DurationVar(&globalOptions.StuckRequestTimeout, "stuck-request-timeout", 5*time.Minute, "`duration` after which to retry stuck requests") // Use our "generate" command instead of the cobra provided "completion" command cmdRoot.CompletionOptions.DisableDefaultCmd = true @@ -494,7 +493,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi } } if err != nil { - if errors.IsFatal(err) || errors.Is(err, repository.ErrNoKeyFound) { + if errors.IsFatal(err) { return nil, err } return nil, errors.Fatalf("%s", err) diff --git a/mover-restic/restic/cmd/restic/integration_test.go b/mover-restic/restic/cmd/restic/integration_test.go index df95031dc..4cecec6bc 100644 --- a/mover-restic/restic/cmd/restic/integration_test.go +++ b/mover-restic/restic/cmd/restic/integration_test.go @@ -80,7 +80,7 @@ func TestListOnce(t *testing.T) { defer cleanup() env.gopts.backendTestHook = func(r backend.Backend) (backend.Backend, error) { - return newOrderedListOnceBackend(r), nil + return newListOnceBackend(r), nil } pruneOpts := PruneOptions{MaxUnused: "0"} checkOpts := CheckOptions{ReadData: true, CheckUnused: true} @@ -148,7 +148,7 @@ func TestFindListOnce(t *testing.T) { defer cleanup() env.gopts.backendTestHook = func(r backend.Backend) (backend.Backend, error) { - return newOrderedListOnceBackend(r), nil + return newListOnceBackend(r), nil } testSetupBackupData(t, env) diff --git a/mover-restic/restic/cmd/restic/main.go b/mover-restic/restic/cmd/restic/main.go index 26e45bb38..5818221a5 100644 --- a/mover-restic/restic/cmd/restic/main.go +++ b/mover-restic/restic/cmd/restic/main.go @@ -17,7 +17,6 @@ import ( "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/feature" "github.com/restic/restic/internal/options" - "github.com/restic/restic/internal/repository" "github.com/restic/restic/internal/restic" ) @@ -83,22 +82,6 @@ The full documentation can be found at https://restic.readthedocs.io/ . }, } -var cmdGroupDefault = "default" -var cmdGroupAdvanced = "advanced" - -func init() { - cmdRoot.AddGroup( - &cobra.Group{ - ID: cmdGroupDefault, - Title: "Available Commands:", - }, - &cobra.Group{ - ID: cmdGroupAdvanced, - Title: "Advanced Options:", - }, - ) -} - // Distinguish commands that need the password from those that work without, // so we don't run $RESTIC_PASSWORD_COMMAND for no reason (it might prompt the // user for authentication). @@ -155,8 +138,6 @@ func main() { fmt.Fprintf(os.Stderr, "Warning: %v\n", err) case errors.IsFatal(err): fmt.Fprintf(os.Stderr, "%v\n", err) - case errors.Is(err, repository.ErrNoKeyFound): - fmt.Fprintf(os.Stderr, "Fatal: %v\n", err) case err != nil: fmt.Fprintf(os.Stderr, "%+v\n", err) @@ -179,8 +160,6 @@ func main() { exitCode = 10 case restic.IsAlreadyLocked(err): exitCode = 11 - case errors.Is(err, repository.ErrNoKeyFound): - exitCode = 12 case errors.Is(err, context.Canceled): exitCode = 130 default: diff --git a/mover-restic/restic/cmd/restic/secondary_repo.go b/mover-restic/restic/cmd/restic/secondary_repo.go index 44621afa1..9a3eb5fe2 100644 --- a/mover-restic/restic/cmd/restic/secondary_repo.go +++ b/mover-restic/restic/cmd/restic/secondary_repo.go @@ -50,7 +50,7 @@ func initSecondaryRepoOptions(f *pflag.FlagSet, opts *secondaryRepoOptions, repo f.StringVarP(&opts.PasswordFile, "from-password-file", "", "", "`file` to read the source repository password from (default: $RESTIC_FROM_PASSWORD_FILE)") f.StringVarP(&opts.KeyHint, "from-key-hint", "", "", "key ID of key to try decrypting the source repository first (default: $RESTIC_FROM_KEY_HINT)") f.StringVarP(&opts.PasswordCommand, "from-password-command", "", "", "shell `command` to obtain the source repository password from (default: $RESTIC_FROM_PASSWORD_COMMAND)") - f.BoolVar(&opts.InsecureNoPassword, "from-insecure-no-password", false, "use an empty password for the source repository (insecure)") + f.BoolVar(&opts.InsecureNoPassword, "from-insecure-no-password", false, "use an empty password for the source repository, must be passed to every restic command (insecure)") opts.Repo = os.Getenv("RESTIC_FROM_REPOSITORY") opts.RepositoryFile = os.Getenv("RESTIC_FROM_REPOSITORY_FILE") diff --git a/mover-restic/restic/doc/030_preparing_a_new_repo.rst b/mover-restic/restic/doc/030_preparing_a_new_repo.rst index fd5b31127..87975f9fa 100644 --- a/mover-restic/restic/doc/030_preparing_a_new_repo.rst +++ b/mover-restic/restic/doc/030_preparing_a_new_repo.rst @@ -249,22 +249,28 @@ while creating the bucket. $ export AWS_ACCESS_KEY_ID= $ export AWS_SECRET_ACCESS_KEY= -When using temporary credentials make sure to include the session token via -the environment variable ``AWS_SESSION_TOKEN``. - You can then easily initialize a repository that uses your Amazon S3 as -a backend. Make sure to use the endpoint for the correct region. The example -uses ``us-east-1``. If the bucket does not exist it will be created in that region: +a backend. If the bucket does not exist it will be created in the +default location: .. code-block:: console - $ restic -r s3:s3.us-east-1.amazonaws.com/bucket_name init + $ restic -r s3:s3.amazonaws.com/bucket_name init enter password for new repository: enter password again: - created restic repository eefee03bbd at s3:s3.us-east-1.amazonaws.com/bucket_name + created restic repository eefee03bbd at s3:s3.amazonaws.com/bucket_name Please note that knowledge of your password is required to access the repository. Losing your password means that your data is irrecoverably lost. +If needed, you can manually specify the region to use by either setting the +environment variable ``AWS_DEFAULT_REGION`` or calling restic with an option +parameter like ``-o s3.region="us-east-1"``. If the region is not specified, +the default region is used. Afterwards, the S3 server (at least for AWS, +``s3.amazonaws.com``) will redirect restic to the correct endpoint. + +When using temporary credentials make sure to include the session token via +then environment variable ``AWS_SESSION_TOKEN``. + Until version 0.8.0, restic used a default prefix of ``restic``, so the files in the bucket were placed in a directory named ``restic``. If you want to access a repository created with an older version of restic, specify the path @@ -272,14 +278,25 @@ after the bucket name like this: .. code-block:: console - $ restic -r s3:s3.us-east-1.amazonaws.com/bucket_name/restic [...] + $ restic -r s3:s3.amazonaws.com/bucket_name/restic [...] +For an S3-compatible server that is not Amazon (like Minio, see below), +or is only available via HTTP, you can specify the URL to the server +like this: ``s3:http://server:port/bucket_name``. + .. note:: restic expects `path-style URLs `__ - like for example ``s3.us-west-2.amazonaws.com/bucket_name`` for Amazon S3. + like for example ``s3.us-west-2.amazonaws.com/bucket_name``. Virtual-hosted–style URLs like ``bucket_name.s3.us-west-2.amazonaws.com``, where the bucket name is part of the hostname are not supported. These must be converted to path-style URLs instead, for example ``s3.us-west-2.amazonaws.com/bucket_name``. - See below for configuration options for S3-compatible storage from other providers. + +.. note:: Certain S3-compatible servers do not properly implement the + ``ListObjectsV2`` API, most notably Ceph versions before v14.2.5. On these + backends, as a temporary workaround, you can provide the + ``-o s3.list-objects-v1=true`` option to use the older + ``ListObjects`` API instead. This option may be removed in future + versions of restic. + Minio Server ************ @@ -304,66 +321,81 @@ this command. .. code-block:: console - $ restic -r s3:http://localhost:9000/restic init + $ ./restic -r s3:http://localhost:9000/restic init enter password for new repository: enter password again: - created restic repository 6ad29560f5 at s3:http://localhost:9000/restic + created restic repository 6ad29560f5 at s3:http://localhost:9000/restic1 Please note that knowledge of your password is required to access the repository. Losing your password means that your data is irrecoverably lost. -S3-compatible Storage -********************* - -For an S3-compatible server that is not Amazon, you can specify the URL to the server -like this: ``s3:https://server:port/bucket_name``. - -If needed, you can manually specify the region to use by either setting the -environment variable ``AWS_DEFAULT_REGION`` or calling restic with an option -parameter like ``-o s3.region="us-east-1"``. If the region is not specified, -the default region ``us-east-1`` is used. +Wasabi +************ -To select between path-style and virtual-hosted access, the extended option -``-o s3.bucket-lookup=auto`` can be used. It supports the following values: +`Wasabi `__ is a low cost Amazon S3 conformant object storage provider. +Due to its S3 conformance, Wasabi can be used as a storage provider for a restic repository. -- ``auto``: Default behavior. Uses ``dns`` for Amazon and Google endpoints. Uses - ``path`` for all other endpoints -- ``dns``: Use virtual-hosted-style bucket access -- ``path``: Use path-style bucket access +- Create a Wasabi bucket using the `Wasabi Console `__. +- Determine the correct Wasabi service URL for your bucket `here `__. -Certain S3-compatible servers do not properly implement the ``ListObjectsV2`` API, -most notably Ceph versions before v14.2.5. On these backends, as a temporary -workaround, you can provide the ``-o s3.list-objects-v1=true`` option to use the -older ``ListObjects`` API instead. This option may be removed in future versions -of restic. +You must first setup the following environment variables with the +credentials of your Wasabi account. -Wasabi -****** +.. code-block:: console -S3 storage from `Wasabi `__ can be used as follows. + $ export AWS_ACCESS_KEY_ID= + $ export AWS_SECRET_ACCESS_KEY= -- Determine the correct Wasabi service URL for your bucket `here `__. -- Set environment variables with the necessary account credentials +Now you can easily initialize restic to use Wasabi as a backend with +this command. .. code-block:: console - $ export AWS_ACCESS_KEY_ID= - $ export AWS_SECRET_ACCESS_KEY= - $ restic -r s3:https:/// init + $ ./restic -r s3:https:/// init + enter password for new repository: + enter password again: + created restic repository xxxxxxxxxx at s3:https:/// + Please note that knowledge of your password is required to access + the repository. Losing your password means that your data is irrecoverably lost. Alibaba Cloud (Aliyun) Object Storage System (OSS) ************************************************** -S3 storage from `Alibaba OSS `__ can be used as follows. +`Alibaba OSS `__ is an +encrypted, secure, cost-effective, and easy-to-use object storage +service that enables you to store, back up, and archive large amounts +of data in the cloud. + +Alibaba OSS is S3 compatible so it can be used as a storage provider +for a restic repository with a couple of extra parameters. -- Determine the correct `Alibaba OSS region endpoint `__ - this will be something like ``oss-eu-west-1.aliyuncs.com`` -- You will need the region name too - this will be something like ``oss-eu-west-1`` -- Set environment variables with the necessary account credentials +- Determine the correct `Alibaba OSS region endpoint `__ - this will be something like ``oss-eu-west-1.aliyuncs.com`` +- You'll need the region name too - this will be something like ``oss-eu-west-1`` + +You must first setup the following environment variables with the +credentials of your Alibaba OSS account. .. code-block:: console $ export AWS_ACCESS_KEY_ID= $ export AWS_SECRET_ACCESS_KEY= - $ restic -o s3.bucket-lookup=dns -o s3.region= -r s3:https:/// init + +Now you can easily initialize restic to use Alibaba OSS as a backend with +this command. + +.. code-block:: console + + $ ./restic -o s3.bucket-lookup=dns -o s3.region= -r s3:https:/// init + enter password for new backend: + enter password again: + created restic backend xxxxxxxxxx at s3:https:/// + Please note that knowledge of your password is required to access + the repository. Losing your password means that your data is irrecoverably lost. + +For example with an actual endpoint: + +.. code-block:: console + + $ restic -o s3.bucket-lookup=dns -o s3.region=oss-eu-west-1 -r s3:https://oss-eu-west-1.aliyuncs.com/bucketname init OpenStack Swift *************** diff --git a/mover-restic/restic/doc/040_backup.rst b/mover-restic/restic/doc/040_backup.rst index 696b235cc..81d99e071 100644 --- a/mover-restic/restic/doc/040_backup.rst +++ b/mover-restic/restic/doc/040_backup.rst @@ -584,13 +584,11 @@ Reading data from a command Sometimes, it can be useful to directly save the output of a program, for example, ``mysqldump`` so that the SQL can later be restored. Restic supports this mode of operation; just supply the option ``--stdin-from-command`` when using the -``backup`` action, and write the command in place of the files/directories. To prevent -restic from interpreting the arguments for the command, make sure to add ``--`` before -the command starts: +``backup`` action, and write the command in place of the files/directories: .. code-block:: console - $ restic -r /srv/restic-repo backup --stdin-from-command -- mysqldump --host example mydb [...] + $ restic -r /srv/restic-repo backup --stdin-from-command mysqldump [...] This command creates a new snapshot based on the standard output of ``mysqldump``. By default, the command's standard output is saved in a file named ``stdin``. @@ -598,7 +596,7 @@ A different name can be specified with ``--stdin-filename``: .. code-block:: console - $ restic -r /srv/restic-repo backup --stdin-filename production.sql --stdin-from-command -- mysqldump --host example mydb [...] + $ restic -r /srv/restic-repo backup --stdin-filename production.sql --stdin-from-command mysqldump [...] Restic uses the command exit code to determine whether the command succeeded. A non-zero exit code from the command causes restic to cancel the backup. This causes @@ -686,30 +684,6 @@ created as it would only be written at the very (successful) end of the backup operation. Previous snapshots will still be there and will still work. -Exit status codes -***************** - -Restic returns an exit status code after the backup command is run: - -* 0 when the backup was successful (snapshot with all source files created) -* 1 when there was a fatal error (no snapshot created) -* 3 when some source files could not be read (incomplete snapshot with remaining files created) -* further exit codes are documented in :ref:`exit-codes`. - -Fatal errors occur for example when restic is unable to write to the backup destination, when -there are network connectivity issues preventing successful communication, or when an invalid -password or command line argument is provided. When restic returns this exit status code, one -should not expect a snapshot to have been created. - -Source file read errors occur when restic fails to read one or more files or directories that -it was asked to back up, e.g. due to permission problems. Restic displays the number of source -file read errors that occurred while running the backup. If there are errors of this type, -restic will still try to complete the backup run with all the other files, and create a -snapshot that then contains all but the unreadable files. - -For use of these exit status codes in scripts and other automation tools, see :ref:`exit-codes`. -To manually inspect the exit code in e.g. Linux, run ``echo $?``. - Environment Variables ********************* @@ -728,7 +702,6 @@ environment variables. The following lists these environment variables: RESTIC_TLS_CLIENT_CERT Location of TLS client certificate and private key (replaces --tls-client-cert) RESTIC_CACHE_DIR Location of the cache directory RESTIC_COMPRESSION Compression mode (only available for repository format version 2) - RESTIC_HOST Only consider snapshots for this host / Set the hostname for the snapshot manually (replaces --host) RESTIC_PROGRESS_FPS Frames per second by which the progress bar is updated RESTIC_PACK_SIZE Target size for pack files RESTIC_READ_CONCURRENCY Concurrency for file reads @@ -798,3 +771,26 @@ See :ref:`caching` for the rules concerning cache locations when The external programs that restic may execute include ``rclone`` (for rclone backends) and ``ssh`` (for the SFTP backend). These may respond to further environment variables and configuration files; see their respective manuals. + +Exit status codes +***************** + +Restic returns one of the following exit status codes after the backup command is run: + +* 0 when the backup was successful (snapshot with all source files created) +* 1 when there was a fatal error (no snapshot created) +* 3 when some source files could not be read (incomplete snapshot with remaining files created) + +Fatal errors occur for example when restic is unable to write to the backup destination, when +there are network connectivity issues preventing successful communication, or when an invalid +password or command line argument is provided. When restic returns this exit status code, one +should not expect a snapshot to have been created. + +Source file read errors occur when restic fails to read one or more files or directories that +it was asked to back up, e.g. due to permission problems. Restic displays the number of source +file read errors that occurred while running the backup. If there are errors of this type, +restic will still try to complete the backup run with all the other files, and create a +snapshot that then contains all but the unreadable files. + +One can use these exit status codes in scripts and other automation tools, to make them aware of +the outcome of the backup run. To manually inspect the exit code in e.g. Linux, run ``echo $?``. diff --git a/mover-restic/restic/doc/045_working_with_repos.rst b/mover-restic/restic/doc/045_working_with_repos.rst index f31e75c84..8dba8439f 100644 --- a/mover-restic/restic/doc/045_working_with_repos.rst +++ b/mover-restic/restic/doc/045_working_with_repos.rst @@ -305,13 +305,6 @@ In order to preview the changes which ``rewrite`` would make, you can use the modifying the repository. Instead restic will only print the actions it would perform. -.. note:: The ``rewrite`` command verifies that it does not modify snapshots in - unexpected ways and fails with an ``cannot encode tree at "[...]" without loosing information`` - error otherwise. This can occur when rewriting a snapshot created by a newer - version of restic or some third-party implementation. - - To convert a snapshot into the format expected by the ``rewrite`` command - use ``restic repair snapshots ``. Modifying metadata of snapshots =============================== diff --git a/mover-restic/restic/doc/075_scripting.rst b/mover-restic/restic/doc/075_scripting.rst index 9fa0da6d0..87ae4fcf4 100644 --- a/mover-restic/restic/doc/075_scripting.rst +++ b/mover-restic/restic/doc/075_scripting.rst @@ -39,8 +39,6 @@ Note that restic will also return exit code ``1`` if a different error is encoun If there are no errors, restic will return a zero exit code and print the repository metadata. -.. _exit-codes: - Exit codes ********** @@ -65,8 +63,6 @@ a more specific description. +-----+----------------------------------------------------+ | 11 | Failed to lock repository (since restic 0.17.0) | +-----+----------------------------------------------------+ -| 12 | Wrong password (since restic 0.17.1) | -+-----+----------------------------------------------------+ | 130 | Restic was interrupted using SIGINT or SIGSTOP | +-----+----------------------------------------------------+ @@ -143,7 +139,7 @@ Error +----------------------+-------------------------------------------+ | ``message_type`` | Always "error" | +----------------------+-------------------------------------------+ -| ``error.message`` | Error message | +| ``error`` | Error message | +----------------------+-------------------------------------------+ | ``during`` | What restic was trying to do | +----------------------+-------------------------------------------+ @@ -543,19 +539,6 @@ Status |``bytes_skipped`` | Total size of skipped files | +----------------------+------------------------------------------------------------+ -Error -^^^^^ - -+----------------------+-------------------------------------------+ -| ``message_type`` | Always "error" | -+----------------------+-------------------------------------------+ -| ``error.message`` | Error message | -+----------------------+-------------------------------------------+ -| ``during`` | Always "restore" | -+----------------------+-------------------------------------------+ -| ``item`` | Usually, the path of the problematic file | -+----------------------+-------------------------------------------+ - Verbose Status ^^^^^^^^^^^^^^ diff --git a/mover-restic/restic/doc/bash-completion.sh b/mover-restic/restic/doc/bash-completion.sh index 0517fdf7c..9d64871ca 100644 --- a/mover-restic/restic/doc/bash-completion.sh +++ b/mover-restic/restic/doc/bash-completion.sh @@ -516,8 +516,6 @@ _restic_backup() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -594,8 +592,6 @@ _restic_cache() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -664,8 +660,6 @@ _restic_cat() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -673,15 +667,6 @@ _restic_cat() must_have_one_flag=() must_have_one_noun=() - must_have_one_noun+=("blob") - must_have_one_noun+=("config") - must_have_one_noun+=("index") - must_have_one_noun+=("key") - must_have_one_noun+=("lock") - must_have_one_noun+=("masterkey") - must_have_one_noun+=("pack") - must_have_one_noun+=("snapshot") - must_have_one_noun+=("tree") noun_aliases=() } @@ -751,8 +736,6 @@ _restic_check() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -857,8 +840,6 @@ _restic_copy() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -929,8 +910,6 @@ _restic_diff() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1025,78 +1004,6 @@ _restic_dump() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") - flags+=("--tls-client-cert=") - two_word_flags+=("--tls-client-cert") - flags+=("--verbose") - flags+=("-v") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_restic_features() -{ - last_command="restic_features" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--help") - flags+=("-h") - local_nonpersistent_flags+=("--help") - local_nonpersistent_flags+=("-h") - flags+=("--cacert=") - two_word_flags+=("--cacert") - flags+=("--cache-dir=") - two_word_flags+=("--cache-dir") - flags+=("--cleanup-cache") - flags+=("--compression=") - two_word_flags+=("--compression") - flags+=("--http-user-agent=") - two_word_flags+=("--http-user-agent") - flags+=("--insecure-no-password") - flags+=("--insecure-tls") - flags+=("--json") - flags+=("--key-hint=") - two_word_flags+=("--key-hint") - flags+=("--limit-download=") - two_word_flags+=("--limit-download") - flags+=("--limit-upload=") - two_word_flags+=("--limit-upload") - flags+=("--no-cache") - flags+=("--no-extra-verify") - flags+=("--no-lock") - flags+=("--option=") - two_word_flags+=("--option") - two_word_flags+=("-o") - flags+=("--pack-size=") - two_word_flags+=("--pack-size") - flags+=("--password-command=") - two_word_flags+=("--password-command") - flags+=("--password-file=") - two_word_flags+=("--password-file") - two_word_flags+=("-p") - flags+=("--quiet") - flags+=("-q") - flags+=("--repo=") - two_word_flags+=("--repo") - two_word_flags+=("-r") - flags+=("--repository-file=") - two_word_flags+=("--repository-file") - flags+=("--retry-lock=") - two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1215,8 +1122,6 @@ _restic_find() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1393,8 +1298,6 @@ _restic_forget() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1483,8 +1386,6 @@ _restic_generate() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1549,8 +1450,6 @@ _restic_help() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1648,8 +1547,6 @@ _restic_init() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1732,8 +1629,6 @@ _restic_key_add() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1798,8 +1693,6 @@ _restic_key_help() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1869,8 +1762,6 @@ _restic_key_list() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -1953,8 +1844,6 @@ _restic_key_passwd() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2023,8 +1912,6 @@ _restic_key_remove() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2098,8 +1985,6 @@ _restic_key() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2168,8 +2053,6 @@ _restic_list() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2262,8 +2145,6 @@ _restic_ls() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2336,8 +2217,6 @@ _restic_migrate() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2434,78 +2313,6 @@ _restic_mount() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") - flags+=("--tls-client-cert=") - two_word_flags+=("--tls-client-cert") - flags+=("--verbose") - flags+=("-v") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_restic_options() -{ - last_command="restic_options" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--help") - flags+=("-h") - local_nonpersistent_flags+=("--help") - local_nonpersistent_flags+=("-h") - flags+=("--cacert=") - two_word_flags+=("--cacert") - flags+=("--cache-dir=") - two_word_flags+=("--cache-dir") - flags+=("--cleanup-cache") - flags+=("--compression=") - two_word_flags+=("--compression") - flags+=("--http-user-agent=") - two_word_flags+=("--http-user-agent") - flags+=("--insecure-no-password") - flags+=("--insecure-tls") - flags+=("--json") - flags+=("--key-hint=") - two_word_flags+=("--key-hint") - flags+=("--limit-download=") - two_word_flags+=("--limit-download") - flags+=("--limit-upload=") - two_word_flags+=("--limit-upload") - flags+=("--no-cache") - flags+=("--no-extra-verify") - flags+=("--no-lock") - flags+=("--option=") - two_word_flags+=("--option") - two_word_flags+=("-o") - flags+=("--pack-size=") - two_word_flags+=("--pack-size") - flags+=("--password-command=") - two_word_flags+=("--password-command") - flags+=("--password-file=") - two_word_flags+=("--password-file") - two_word_flags+=("-p") - flags+=("--quiet") - flags+=("-q") - flags+=("--repo=") - two_word_flags+=("--repo") - two_word_flags+=("-r") - flags+=("--repository-file=") - two_word_flags+=("--repository-file") - flags+=("--retry-lock=") - two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2596,8 +2403,6 @@ _restic_prune() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2666,8 +2471,6 @@ _restic_recover() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2732,8 +2535,6 @@ _restic_repair_help() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2805,8 +2606,6 @@ _restic_repair_index() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2875,8 +2674,6 @@ _restic_repair_packs() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -2965,8 +2762,6 @@ _restic_repair_snapshots() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3039,8 +2834,6 @@ _restic_repair() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3177,8 +2970,6 @@ _restic_restore() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3293,8 +3084,6 @@ _restic_rewrite() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3367,8 +3156,6 @@ _restic_self-update() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3465,8 +3252,6 @@ _restic_snapshots() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3503,8 +3288,6 @@ _restic_stats() local_nonpersistent_flags+=("-H") flags+=("--mode=") two_word_flags+=("--mode") - flags_with_completion+=("--mode") - flags_completion+=("__restic_handle_go_custom_completion") local_nonpersistent_flags+=("--mode") local_nonpersistent_flags+=("--mode=") flags+=("--path=") @@ -3555,8 +3338,6 @@ _restic_stats() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3651,8 +3432,6 @@ _restic_tag() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3723,8 +3502,6 @@ _restic_unlock() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3793,8 +3570,6 @@ _restic_version() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") @@ -3819,7 +3594,6 @@ _restic_root_command() commands+=("copy") commands+=("diff") commands+=("dump") - commands+=("features") commands+=("find") commands+=("forget") commands+=("generate") @@ -3830,7 +3604,6 @@ _restic_root_command() commands+=("ls") commands+=("migrate") commands+=("mount") - commands+=("options") commands+=("prune") commands+=("recover") commands+=("repair") @@ -3893,8 +3666,6 @@ _restic_root_command() two_word_flags+=("--repository-file") flags+=("--retry-lock=") two_word_flags+=("--retry-lock") - flags+=("--stuck-request-timeout=") - two_word_flags+=("--stuck-request-timeout") flags+=("--tls-client-cert=") two_word_flags+=("--tls-client-cert") flags+=("--verbose") diff --git a/mover-restic/restic/doc/design.rst b/mover-restic/restic/doc/design.rst index c974e997a..7fb8b71b2 100644 --- a/mover-restic/restic/doc/design.rst +++ b/mover-restic/restic/doc/design.rst @@ -126,8 +126,8 @@ the option ``-o local.layout=default``, valid values are ``default`` and ``s3legacy``. The option for the sftp backend is named ``sftp.layout``, for the s3 backend ``s3.layout``. -S3 Legacy Layout (deprecated) ------------------------------ +S3 Legacy Layout +---------------- Unfortunately during development the Amazon S3 backend uses slightly different paths (directory names use singular instead of plural for ``key``, @@ -152,7 +152,8 @@ the ``data`` directory. The S3 Legacy repository layout looks like this: /snapshot └── 22a5af1bdc6e616f8a29579458c49627e01b32210d09adb288d1ecda7c5711ec -Restic 0.17 is the last version that supports the legacy layout. +The S3 backend understands and accepts both forms, new backends are +always created with the default layout for compatibility reasons. Pack Format =========== @@ -233,9 +234,7 @@ Individual files for the index, locks or snapshots are encrypted and authenticated like Data and Tree Blobs, so the outer structure is ``IV || Ciphertext || MAC`` again. In repository format version 1 the plaintext always consists of a JSON document which must either be an -object or an array. The JSON encoder must deterministically encode the -document and should match the behavior of the Go standard library implementation -in ``encoding/json``. +object or an array. Repository format version 2 adds support for compression. The plaintext now starts with a header to indicate the encoding version to distinguish @@ -474,10 +473,6 @@ A snapshot references a tree by the SHA-256 hash of the JSON string representation of its contents. Trees and data are saved in pack files in a subdirectory of the directory ``data``. -The JSON encoder must deterministically encode the document and should -match the behavior of the Go standard library implementation in ``encoding/json``. -This ensures that trees can be properly deduplicated. - The command ``restic cat blob`` can be used to inspect the tree referenced above (piping the output of the command to ``jq .`` so that the JSON is indented): @@ -512,11 +507,12 @@ this metadata is generated: - The name is quoted using `strconv.Quote `__ before being saved. This handles non-unicode names, but also changes the representation of names containing ``"`` or ``\``. + - The filemode saved is the mode defined by `fs.FileMode `__ masked by ``os.ModePerm | os.ModeType | os.ModeSetuid | os.ModeSetgid | os.ModeSticky`` -- When the entry references a directory, the field ``subtree`` contains the plain text - ID of another tree object. -- Check the implementation for a full struct definition. + +When the entry references a directory, the field ``subtree`` contains the plain text +ID of another tree object. When the command ``restic cat blob`` is used, the plaintext ID is needed to print a tree. The tree referenced above can be dumped as follows: diff --git a/mover-restic/restic/doc/faq.rst b/mover-restic/restic/doc/faq.rst index 74dd77d71..19879d817 100644 --- a/mover-restic/restic/doc/faq.rst +++ b/mover-restic/restic/doc/faq.rst @@ -90,7 +90,7 @@ The error here is that the tilde ``~`` in ``"~/documents"`` didn't get expanded /home/john/documents $ echo "~/documents" - ~/documents + ~/document $ echo "$HOME/documents" /home/john/documents @@ -228,17 +228,3 @@ Restic backup command fails to find a valid file in Windows If the name of a file in Windows contains an invalid character, Restic will not be able to read the file. To solve this issue, consider renaming the particular file. - -What can I do in case of "request timeout" errors? --------------------------------------------------- - -Restic monitors connections to the backend to detect stuck requests. If a request -does not return any data within five minutes, restic assumes the request is stuck and -retries it. However, for large repositories it sometimes takes longer than that to -collect a list of all files, causing the following error: - -:: - - List(data) returned error, retrying after 1s: [...]: request timeout - -In this case you can increase the timeout using the ``--stuck-request-timeout`` option. diff --git a/mover-restic/restic/doc/man/restic-backup.1 b/mover-restic/restic/doc/man/restic-backup.1 index a84b955ba..cda4aadff 100644 --- a/mover-restic/restic/doc/man/restic-backup.1 +++ b/mover-restic/restic/doc/man/restic-backup.1 @@ -24,7 +24,6 @@ Exit status is 1 if there was a fatal error (no snapshot created). Exit status is 3 if some source data could not be read (incomplete snapshot created). Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -230,10 +229,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-cache.1 b/mover-restic/restic/doc/man/restic-cache.1 index fb23fe8a9..f868b8a6b 100644 --- a/mover-restic/restic/doc/man/restic-cache.1 +++ b/mover-restic/restic/doc/man/restic-cache.1 @@ -129,10 +129,6 @@ Exit status is 1 if there was any error. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-cat.1 b/mover-restic/restic/doc/man/restic-cat.1 index cab1b85a5..2298c58cf 100644 --- a/mover-restic/restic/doc/man/restic-cat.1 +++ b/mover-restic/restic/doc/man/restic-cat.1 @@ -22,7 +22,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -120,10 +119,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-check.1 b/mover-restic/restic/doc/man/restic-check.1 index 60d17a313..c0d1b07a8 100644 --- a/mover-restic/restic/doc/man/restic-check.1 +++ b/mover-restic/restic/doc/man/restic-check.1 @@ -27,7 +27,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -137,10 +136,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-copy.1 b/mover-restic/restic/doc/man/restic-copy.1 index 96c394139..63b67e5e7 100644 --- a/mover-restic/restic/doc/man/restic-copy.1 +++ b/mover-restic/restic/doc/man/restic-copy.1 @@ -36,13 +36,12 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS .PP \fB--from-insecure-no-password\fP[=false] - use an empty password for the source repository (insecure) + use an empty password for the source repository, must be passed to every restic command (insecure) .PP \fB--from-key-hint\fP="" @@ -170,10 +169,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-diff.1 b/mover-restic/restic/doc/man/restic-diff.1 index f4c8a1d14..f4ffa2737 100644 --- a/mover-restic/restic/doc/man/restic-diff.1 +++ b/mover-restic/restic/doc/man/restic-diff.1 @@ -49,7 +49,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -151,10 +150,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-dump.1 b/mover-restic/restic/doc/man/restic-dump.1 index 657570f6d..00cb3c8b6 100644 --- a/mover-restic/restic/doc/man/restic-dump.1 +++ b/mover-restic/restic/doc/man/restic-dump.1 @@ -34,7 +34,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -152,10 +151,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-features.1 b/mover-restic/restic/doc/man/restic-features.1 deleted file mode 100644 index b288f655a..000000000 --- a/mover-restic/restic/doc/man/restic-features.1 +++ /dev/null @@ -1,146 +0,0 @@ -.nh -.TH "restic backup" "1" "Jan 2017" "generated by \fBrestic generate\fR" "" - -.SH NAME -.PP -restic-features - Print list of feature flags - - -.SH SYNOPSIS -.PP -\fBrestic features [flags]\fP - - -.SH DESCRIPTION -.PP -The "features" command prints a list of supported feature flags. - -.PP -To pass feature flags to restic, set the RESTIC_FEATURES environment variable -to "featureA=true,featureB=false". Specifying an unknown feature flag is an error. - -.PP -A feature can either be in alpha, beta, stable or deprecated state. -An \fIalpha\fP feature is disabled by default and may change in arbitrary ways between restic versions or be removed. -A \fIbeta\fP feature is enabled by default, but still can change in minor ways or be removed. -A \fIstable\fP feature is always enabled and cannot be disabled. The flag will be removed in a future restic version. -A \fIdeprecated\fP feature is always disabled and cannot be enabled. The flag will be removed in a future restic version. - - -.SH EXIT STATUS -.PP -Exit status is 0 if the command was successful. -Exit status is 1 if there was any error. - - -.SH OPTIONS -.PP -\fB-h\fP, \fB--help\fP[=false] - help for features - - -.SH OPTIONS INHERITED FROM PARENT COMMANDS -.PP -\fB--cacert\fP=[] - \fBfile\fR to load root certificates from (default: use system certificates or $RESTIC_CACERT) - -.PP -\fB--cache-dir\fP="" - set the cache \fBdirectory\fR\&. (default: use system default cache directory) - -.PP -\fB--cleanup-cache\fP[=false] - auto remove old cache directories - -.PP -\fB--compression\fP=auto - compression mode (only available for repository format version 2), one of (auto|off|max) (default: $RESTIC_COMPRESSION) - -.PP -\fB--http-user-agent\fP="" - set a http user agent for outgoing http requests - -.PP -\fB--insecure-no-password\fP[=false] - use an empty password for the repository, must be passed to every restic command (insecure) - -.PP -\fB--insecure-tls\fP[=false] - skip TLS certificate verification when connecting to the repository (insecure) - -.PP -\fB--json\fP[=false] - set output mode to JSON for commands that support it - -.PP -\fB--key-hint\fP="" - \fBkey\fR ID of key to try decrypting first (default: $RESTIC_KEY_HINT) - -.PP -\fB--limit-download\fP=0 - limits downloads to a maximum \fBrate\fR in KiB/s. (default: unlimited) - -.PP -\fB--limit-upload\fP=0 - limits uploads to a maximum \fBrate\fR in KiB/s. (default: unlimited) - -.PP -\fB--no-cache\fP[=false] - do not use a local cache - -.PP -\fB--no-extra-verify\fP[=false] - skip additional verification of data before upload (see documentation) - -.PP -\fB--no-lock\fP[=false] - do not lock the repository, this allows some operations on read-only repositories - -.PP -\fB-o\fP, \fB--option\fP=[] - set extended option (\fBkey=value\fR, can be specified multiple times) - -.PP -\fB--pack-size\fP=0 - set target pack \fBsize\fR in MiB, created pack files may be larger (default: $RESTIC_PACK_SIZE) - -.PP -\fB--password-command\fP="" - shell \fBcommand\fR to obtain the repository password from (default: $RESTIC_PASSWORD_COMMAND) - -.PP -\fB-p\fP, \fB--password-file\fP="" - \fBfile\fR to read the repository password from (default: $RESTIC_PASSWORD_FILE) - -.PP -\fB-q\fP, \fB--quiet\fP[=false] - do not output comprehensive progress report - -.PP -\fB-r\fP, \fB--repo\fP="" - \fBrepository\fR to backup to or restore from (default: $RESTIC_REPOSITORY) - -.PP -\fB--repository-file\fP="" - \fBfile\fR to read the repository location from (default: $RESTIC_REPOSITORY_FILE) - -.PP -\fB--retry-lock\fP=0s - retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) - -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - -.PP -\fB--tls-client-cert\fP="" - path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) - -.PP -\fB-v\fP, \fB--verbose\fP[=0] - be verbose (specify multiple times or a level using --verbose=n``, max level/times is 2) - - -.SH SEE ALSO -.PP -\fBrestic(1)\fP diff --git a/mover-restic/restic/doc/man/restic-find.1 b/mover-restic/restic/doc/man/restic-find.1 index e8d974527..2d81decd3 100644 --- a/mover-restic/restic/doc/man/restic-find.1 +++ b/mover-restic/restic/doc/man/restic-find.1 @@ -165,10 +165,6 @@ It can also be used to search for restic blobs or trees for troubleshooting. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) @@ -194,7 +190,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .EE diff --git a/mover-restic/restic/doc/man/restic-forget.1 b/mover-restic/restic/doc/man/restic-forget.1 index 058dbee25..55705288f 100644 --- a/mover-restic/restic/doc/man/restic-forget.1 +++ b/mover-restic/restic/doc/man/restic-forget.1 @@ -36,7 +36,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -238,10 +237,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-generate.1 b/mover-restic/restic/doc/man/restic-generate.1 index f17a6fcd0..f2db39bac 100644 --- a/mover-restic/restic/doc/man/restic-generate.1 +++ b/mover-restic/restic/doc/man/restic-generate.1 @@ -138,10 +138,6 @@ Exit status is 1 if there was any error. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-init.1 b/mover-restic/restic/doc/man/restic-init.1 index 50fa00b71..de439add5 100644 --- a/mover-restic/restic/doc/man/restic-init.1 +++ b/mover-restic/restic/doc/man/restic-init.1 @@ -29,7 +29,7 @@ Exit status is 1 if there was any error. .PP \fB--from-insecure-no-password\fP[=false] - use an empty password for the source repository (insecure) + use an empty password for the source repository, must be passed to every restic command (insecure) .PP \fB--from-key-hint\fP="" @@ -149,10 +149,6 @@ Exit status is 1 if there was any error. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-key-add.1 b/mover-restic/restic/doc/man/restic-key-add.1 index ff33408b4..6a24e1e67 100644 --- a/mover-restic/restic/doc/man/restic-key-add.1 +++ b/mover-restic/restic/doc/man/restic-key-add.1 @@ -22,7 +22,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -136,10 +135,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-key-list.1 b/mover-restic/restic/doc/man/restic-key-list.1 index 7deb05793..a00b116b9 100644 --- a/mover-restic/restic/doc/man/restic-key-list.1 +++ b/mover-restic/restic/doc/man/restic-key-list.1 @@ -24,7 +24,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -122,10 +121,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-key-passwd.1 b/mover-restic/restic/doc/man/restic-key-passwd.1 index 68e81edd9..42315d72a 100644 --- a/mover-restic/restic/doc/man/restic-key-passwd.1 +++ b/mover-restic/restic/doc/man/restic-key-passwd.1 @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -137,10 +136,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-key-remove.1 b/mover-restic/restic/doc/man/restic-key-remove.1 index ff1a0ceb9..6ee826059 100644 --- a/mover-restic/restic/doc/man/restic-key-remove.1 +++ b/mover-restic/restic/doc/man/restic-key-remove.1 @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -121,10 +120,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-key.1 b/mover-restic/restic/doc/man/restic-key.1 index 4fd1f6caf..43da808cc 100644 --- a/mover-restic/restic/doc/man/restic-key.1 +++ b/mover-restic/restic/doc/man/restic-key.1 @@ -112,10 +112,6 @@ per repository. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-list.1 b/mover-restic/restic/doc/man/restic-list.1 index 29945e859..f8a1db005 100644 --- a/mover-restic/restic/doc/man/restic-list.1 +++ b/mover-restic/restic/doc/man/restic-list.1 @@ -22,7 +22,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -120,10 +119,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-ls.1 b/mover-restic/restic/doc/man/restic-ls.1 index b990d2ec8..6cc662583 100644 --- a/mover-restic/restic/doc/man/restic-ls.1 +++ b/mover-restic/restic/doc/man/restic-ls.1 @@ -37,7 +37,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -163,10 +162,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-migrate.1 b/mover-restic/restic/doc/man/restic-migrate.1 index c0fa2dbc1..2272294bf 100644 --- a/mover-restic/restic/doc/man/restic-migrate.1 +++ b/mover-restic/restic/doc/man/restic-migrate.1 @@ -24,7 +24,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -126,10 +125,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-mount.1 b/mover-restic/restic/doc/man/restic-mount.1 index 5ec59391d..a256d2a5f 100644 --- a/mover-restic/restic/doc/man/restic-mount.1 +++ b/mover-restic/restic/doc/man/restic-mount.1 @@ -64,7 +64,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -194,10 +193,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-options.1 b/mover-restic/restic/doc/man/restic-options.1 deleted file mode 100644 index 8ea8bea63..000000000 --- a/mover-restic/restic/doc/man/restic-options.1 +++ /dev/null @@ -1,135 +0,0 @@ -.nh -.TH "restic backup" "1" "Jan 2017" "generated by \fBrestic generate\fR" "" - -.SH NAME -.PP -restic-options - Print list of extended options - - -.SH SYNOPSIS -.PP -\fBrestic options [flags]\fP - - -.SH DESCRIPTION -.PP -The "options" command prints a list of extended options. - - -.SH EXIT STATUS -.PP -Exit status is 0 if the command was successful. -Exit status is 1 if there was any error. - - -.SH OPTIONS -.PP -\fB-h\fP, \fB--help\fP[=false] - help for options - - -.SH OPTIONS INHERITED FROM PARENT COMMANDS -.PP -\fB--cacert\fP=[] - \fBfile\fR to load root certificates from (default: use system certificates or $RESTIC_CACERT) - -.PP -\fB--cache-dir\fP="" - set the cache \fBdirectory\fR\&. (default: use system default cache directory) - -.PP -\fB--cleanup-cache\fP[=false] - auto remove old cache directories - -.PP -\fB--compression\fP=auto - compression mode (only available for repository format version 2), one of (auto|off|max) (default: $RESTIC_COMPRESSION) - -.PP -\fB--http-user-agent\fP="" - set a http user agent for outgoing http requests - -.PP -\fB--insecure-no-password\fP[=false] - use an empty password for the repository, must be passed to every restic command (insecure) - -.PP -\fB--insecure-tls\fP[=false] - skip TLS certificate verification when connecting to the repository (insecure) - -.PP -\fB--json\fP[=false] - set output mode to JSON for commands that support it - -.PP -\fB--key-hint\fP="" - \fBkey\fR ID of key to try decrypting first (default: $RESTIC_KEY_HINT) - -.PP -\fB--limit-download\fP=0 - limits downloads to a maximum \fBrate\fR in KiB/s. (default: unlimited) - -.PP -\fB--limit-upload\fP=0 - limits uploads to a maximum \fBrate\fR in KiB/s. (default: unlimited) - -.PP -\fB--no-cache\fP[=false] - do not use a local cache - -.PP -\fB--no-extra-verify\fP[=false] - skip additional verification of data before upload (see documentation) - -.PP -\fB--no-lock\fP[=false] - do not lock the repository, this allows some operations on read-only repositories - -.PP -\fB-o\fP, \fB--option\fP=[] - set extended option (\fBkey=value\fR, can be specified multiple times) - -.PP -\fB--pack-size\fP=0 - set target pack \fBsize\fR in MiB, created pack files may be larger (default: $RESTIC_PACK_SIZE) - -.PP -\fB--password-command\fP="" - shell \fBcommand\fR to obtain the repository password from (default: $RESTIC_PASSWORD_COMMAND) - -.PP -\fB-p\fP, \fB--password-file\fP="" - \fBfile\fR to read the repository password from (default: $RESTIC_PASSWORD_FILE) - -.PP -\fB-q\fP, \fB--quiet\fP[=false] - do not output comprehensive progress report - -.PP -\fB-r\fP, \fB--repo\fP="" - \fBrepository\fR to backup to or restore from (default: $RESTIC_REPOSITORY) - -.PP -\fB--repository-file\fP="" - \fBfile\fR to read the repository location from (default: $RESTIC_REPOSITORY_FILE) - -.PP -\fB--retry-lock\fP=0s - retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) - -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - -.PP -\fB--tls-client-cert\fP="" - path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) - -.PP -\fB-v\fP, \fB--verbose\fP[=0] - be verbose (specify multiple times or a level using --verbose=n``, max level/times is 2) - - -.SH SEE ALSO -.PP -\fBrestic(1)\fP diff --git a/mover-restic/restic/doc/man/restic-prune.1 b/mover-restic/restic/doc/man/restic-prune.1 index 1ee262b61..7e16748ab 100644 --- a/mover-restic/restic/doc/man/restic-prune.1 +++ b/mover-restic/restic/doc/man/restic-prune.1 @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -149,10 +148,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-recover.1 b/mover-restic/restic/doc/man/restic-recover.1 index 382a91ceb..0529360ae 100644 --- a/mover-restic/restic/doc/man/restic-recover.1 +++ b/mover-restic/restic/doc/man/restic-recover.1 @@ -24,7 +24,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -122,10 +121,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-repair-index.1 b/mover-restic/restic/doc/man/restic-repair-index.1 index 341f90d59..60327a916 100644 --- a/mover-restic/restic/doc/man/restic-repair-index.1 +++ b/mover-restic/restic/doc/man/restic-repair-index.1 @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -125,10 +124,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-repair-packs.1 b/mover-restic/restic/doc/man/restic-repair-packs.1 index d0091725b..01a2f6540 100644 --- a/mover-restic/restic/doc/man/restic-repair-packs.1 +++ b/mover-restic/restic/doc/man/restic-repair-packs.1 @@ -23,7 +23,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -121,10 +120,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-repair-snapshots.1 b/mover-restic/restic/doc/man/restic-repair-snapshots.1 index d9e12ddf1..c4439f131 100644 --- a/mover-restic/restic/doc/man/restic-repair-snapshots.1 +++ b/mover-restic/restic/doc/man/restic-repair-snapshots.1 @@ -41,7 +41,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -159,10 +158,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-repair.1 b/mover-restic/restic/doc/man/restic-repair.1 index b06562486..7fa313aab 100644 --- a/mover-restic/restic/doc/man/restic-repair.1 +++ b/mover-restic/restic/doc/man/restic-repair.1 @@ -111,10 +111,6 @@ Repair the repository \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-restore.1 b/mover-restic/restic/doc/man/restic-restore.1 index e9ef4ef94..876b18bf8 100644 --- a/mover-restic/restic/doc/man/restic-restore.1 +++ b/mover-restic/restic/doc/man/restic-restore.1 @@ -31,7 +31,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -197,10 +196,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-rewrite.1 b/mover-restic/restic/doc/man/restic-rewrite.1 index c0d4a7e1a..d3dd92436 100644 --- a/mover-restic/restic/doc/man/restic-rewrite.1 +++ b/mover-restic/restic/doc/man/restic-rewrite.1 @@ -39,7 +39,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -181,10 +180,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-self-update.1 b/mover-restic/restic/doc/man/restic-self-update.1 index d475f13cb..e6dd4faf2 100644 --- a/mover-restic/restic/doc/man/restic-self-update.1 +++ b/mover-restic/restic/doc/man/restic-self-update.1 @@ -25,7 +25,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -127,10 +126,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-snapshots.1 b/mover-restic/restic/doc/man/restic-snapshots.1 index f59240b44..25d5274e3 100644 --- a/mover-restic/restic/doc/man/restic-snapshots.1 +++ b/mover-restic/restic/doc/man/restic-snapshots.1 @@ -22,7 +22,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -144,10 +143,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-stats.1 b/mover-restic/restic/doc/man/restic-stats.1 index 1e6e79dac..fe4074ca5 100644 --- a/mover-restic/restic/doc/man/restic-stats.1 +++ b/mover-restic/restic/doc/man/restic-stats.1 @@ -52,7 +52,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -166,10 +165,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-tag.1 b/mover-restic/restic/doc/man/restic-tag.1 index 89c677867..7ab1911e5 100644 --- a/mover-restic/restic/doc/man/restic-tag.1 +++ b/mover-restic/restic/doc/man/restic-tag.1 @@ -29,7 +29,6 @@ Exit status is 0 if the command was successful. Exit status is 1 if there was any error. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. -Exit status is 12 if the password is incorrect. .SH OPTIONS @@ -151,10 +150,6 @@ Exit status is 12 if the password is incorrect. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-unlock.1 b/mover-restic/restic/doc/man/restic-unlock.1 index 74679ef91..a24a4f815 100644 --- a/mover-restic/restic/doc/man/restic-unlock.1 +++ b/mover-restic/restic/doc/man/restic-unlock.1 @@ -121,10 +121,6 @@ Exit status is 1 if there was any error. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic-version.1 b/mover-restic/restic/doc/man/restic-version.1 index 8d5fe6c65..e9df439ed 100644 --- a/mover-restic/restic/doc/man/restic-version.1 +++ b/mover-restic/restic/doc/man/restic-version.1 @@ -118,10 +118,6 @@ Exit status is 1 if there was any error. \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) diff --git a/mover-restic/restic/doc/man/restic.1 b/mover-restic/restic/doc/man/restic.1 index bd8009aac..ee423c6ad 100644 --- a/mover-restic/restic/doc/man/restic.1 +++ b/mover-restic/restic/doc/man/restic.1 @@ -113,10 +113,6 @@ The full documentation can be found at https://restic.readthedocs.io/ . \fB--retry-lock\fP=0s retry to lock the repository if it is already locked, takes a value like 5m or 2h (default: no retries) -.PP -\fB--stuck-request-timeout\fP=5m0s - \fBduration\fR after which to retry stuck requests - .PP \fB--tls-client-cert\fP="" path to a \fBfile\fR containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT) @@ -128,4 +124,4 @@ The full documentation can be found at https://restic.readthedocs.io/ . .SH SEE ALSO .PP -\fBrestic-backup(1)\fP, \fBrestic-cache(1)\fP, \fBrestic-cat(1)\fP, \fBrestic-check(1)\fP, \fBrestic-copy(1)\fP, \fBrestic-diff(1)\fP, \fBrestic-dump(1)\fP, \fBrestic-features(1)\fP, \fBrestic-find(1)\fP, \fBrestic-forget(1)\fP, \fBrestic-generate(1)\fP, \fBrestic-init(1)\fP, \fBrestic-key(1)\fP, \fBrestic-list(1)\fP, \fBrestic-ls(1)\fP, \fBrestic-migrate(1)\fP, \fBrestic-mount(1)\fP, \fBrestic-options(1)\fP, \fBrestic-prune(1)\fP, \fBrestic-recover(1)\fP, \fBrestic-repair(1)\fP, \fBrestic-restore(1)\fP, \fBrestic-rewrite(1)\fP, \fBrestic-self-update(1)\fP, \fBrestic-snapshots(1)\fP, \fBrestic-stats(1)\fP, \fBrestic-tag(1)\fP, \fBrestic-unlock(1)\fP, \fBrestic-version(1)\fP +\fBrestic-backup(1)\fP, \fBrestic-cache(1)\fP, \fBrestic-cat(1)\fP, \fBrestic-check(1)\fP, \fBrestic-copy(1)\fP, \fBrestic-diff(1)\fP, \fBrestic-dump(1)\fP, \fBrestic-find(1)\fP, \fBrestic-forget(1)\fP, \fBrestic-generate(1)\fP, \fBrestic-init(1)\fP, \fBrestic-key(1)\fP, \fBrestic-list(1)\fP, \fBrestic-ls(1)\fP, \fBrestic-migrate(1)\fP, \fBrestic-mount(1)\fP, \fBrestic-prune(1)\fP, \fBrestic-recover(1)\fP, \fBrestic-repair(1)\fP, \fBrestic-restore(1)\fP, \fBrestic-rewrite(1)\fP, \fBrestic-self-update(1)\fP, \fBrestic-snapshots(1)\fP, \fBrestic-stats(1)\fP, \fBrestic-tag(1)\fP, \fBrestic-unlock(1)\fP, \fBrestic-version(1)\fP diff --git a/mover-restic/restic/doc/manual_rest.rst b/mover-restic/restic/doc/manual_rest.rst index d1e5817f3..a7a0f96e0 100644 --- a/mover-restic/restic/doc/manual_rest.rst +++ b/mover-restic/restic/doc/manual_rest.rst @@ -8,7 +8,7 @@ Usage help is available: .. code-block:: console - $ restic --help + $ ./restic --help restic is a backup program which allows saving multiple revisions of files and directories in an encrypted repository stored on different backends. @@ -28,6 +28,8 @@ Usage help is available: dump Print a backed-up file to stdout find Find a file, a directory or restic IDs forget Remove snapshots from the repository + generate Generate manual pages and auto-completion files (bash, fish, zsh, powershell) + help Help about any command init Initialize a new repository key Manage keys (passwords) list List objects in the repository @@ -39,19 +41,11 @@ Usage help is available: repair Repair the repository restore Extract the data from a snapshot rewrite Rewrite snapshots to exclude unwanted files + self-update Update the restic binary snapshots List all snapshots stats Scan the repository and show basic statistics tag Modify tags on snapshots unlock Remove locks other processes created - - Advanced Options: - features Print list of feature flags - options Print list of extended options - - Additional Commands: - generate Generate manual pages and auto-completion files (bash, fish, zsh, powershell) - help Help about any command - self-update Update the restic binary version Print version information Flags: @@ -91,7 +85,7 @@ command: .. code-block:: console - $ restic backup --help + $ ./restic backup --help The "backup" command creates a new snapshot and saves the files and directories given as the arguments. diff --git a/mover-restic/restic/internal/archiver/archiver.go b/mover-restic/restic/internal/archiver/archiver.go index e7c346d3a..d9f089e81 100644 --- a/mover-restic/restic/internal/archiver/archiver.go +++ b/mover-restic/restic/internal/archiver/archiver.go @@ -263,8 +263,7 @@ func (arch *Archiver) nodeFromFileInfo(snPath, filename string, fi os.FileInfo, // overwrite name to match that within the snapshot node.Name = path.Base(snPath) if err != nil { - err = fmt.Errorf("incomplete metadata for %v: %w", filename, err) - return node, arch.error(filename, err) + return node, fmt.Errorf("nodeFromFileInfo %v: %w", filename, err) } return node, err } @@ -715,12 +714,7 @@ func resolveRelativeTargets(filesys fs.FS, targets []string) ([]string, error) { debug.Log("targets before resolving: %v", targets) result := make([]string, 0, len(targets)) for _, target := range targets { - if target != "" && filesys.VolumeName(target) == target { - // special case to allow users to also specify a volume name "C:" instead of a path "C:\" - target = target + filesys.Separator() - } else { - target = filesys.Clean(target) - } + target = filesys.Clean(target) pc, _ := pathComponents(filesys, target, false) if len(pc) > 0 { result = append(result, target) diff --git a/mover-restic/restic/internal/archiver/archiver_test.go b/mover-restic/restic/internal/archiver/archiver_test.go index c54f9ea33..f38d5b0de 100644 --- a/mover-restic/restic/internal/archiver/archiver_test.go +++ b/mover-restic/restic/internal/archiver/archiver_test.go @@ -3,7 +3,6 @@ package archiver import ( "bytes" "context" - "fmt" "io" "os" "path/filepath" @@ -1448,66 +1447,6 @@ func TestArchiverSnapshot(t *testing.T) { } } -func TestResolveRelativeTargetsSpecial(t *testing.T) { - var tests = []struct { - name string - targets []string - expected []string - win bool - }{ - { - name: "basic relative path", - targets: []string{filepath.FromSlash("some/path")}, - expected: []string{filepath.FromSlash("some/path")}, - }, - { - name: "partial relative path", - targets: []string{filepath.FromSlash("../some/path")}, - expected: []string{filepath.FromSlash("../some/path")}, - }, - { - name: "basic absolute path", - targets: []string{filepath.FromSlash("/some/path")}, - expected: []string{filepath.FromSlash("/some/path")}, - }, - { - name: "volume name", - targets: []string{"C:"}, - expected: []string{"C:\\"}, - win: true, - }, - { - name: "volume root path", - targets: []string{"C:\\"}, - expected: []string{"C:\\"}, - win: true, - }, - { - name: "UNC path", - targets: []string{"\\\\server\\volume"}, - expected: []string{"\\\\server\\volume\\"}, - win: true, - }, - { - name: "UNC path with trailing slash", - targets: []string{"\\\\server\\volume\\"}, - expected: []string{"\\\\server\\volume\\"}, - win: true, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if test.win && runtime.GOOS != "windows" { - t.Skip("skip test on unix") - } - - targets, err := resolveRelativeTargets(&fs.Local{}, test.targets) - rtest.OK(t, err) - rtest.Equals(t, test.expected, targets) - }) - } -} - func TestArchiverSnapshotSelect(t *testing.T) { var tests = []struct { name string @@ -2399,28 +2338,3 @@ func TestRacyFileSwap(t *testing.T) { t.Errorf("Save() excluded the node, that's unexpected") } } - -func TestMetadataBackupErrorFiltering(t *testing.T) { - tempdir := t.TempDir() - repo := repository.TestRepository(t) - - filename := filepath.Join(tempdir, "file") - rtest.OK(t, os.WriteFile(filename, []byte("example"), 0o600)) - fi, err := os.Stat(filename) - rtest.OK(t, err) - - arch := New(repo, fs.Local{}, Options{}) - - var filteredErr error - replacementErr := fmt.Errorf("replacement") - arch.Error = func(item string, err error) error { - filteredErr = err - return replacementErr - } - - // check that errors from reading extended metadata are properly filtered - node, err := arch.nodeFromFileInfo("file", filename+"invalid", fi, false) - rtest.Assert(t, node != nil, "node is missing") - rtest.Assert(t, err == replacementErr, "expected %v got %v", replacementErr, err) - rtest.Assert(t, filteredErr != nil, "missing inner error") -} diff --git a/mover-restic/restic/internal/backend/cache/backend.go b/mover-restic/restic/internal/backend/cache/backend.go index 3754266ba..63bb6f85f 100644 --- a/mover-restic/restic/internal/backend/cache/backend.go +++ b/mover-restic/restic/internal/backend/cache/backend.go @@ -2,14 +2,11 @@ package cache import ( "context" - "fmt" "io" - "os" "sync" "github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/debug" - "github.com/restic/restic/internal/restic" ) // Backend wraps a restic.Backend and adds a cache. @@ -165,9 +162,7 @@ func (b *Backend) Load(ctx context.Context, h backend.Handle, length int, offset // try loading from cache without checking that the handle is actually cached inCache, err := b.loadFromCache(h, length, offset, consumer) if inCache { - if err != nil { - debug.Log("error loading %v from cache: %v", h, err) - } + debug.Log("error loading %v from cache: %v", h, err) // the caller must explicitly use cache.Forget() to remove the cache entry return err } @@ -218,43 +213,3 @@ func (b *Backend) IsNotExist(err error) bool { func (b *Backend) Unwrap() backend.Backend { return b.Backend } - -func (b *Backend) List(ctx context.Context, t backend.FileType, fn func(f backend.FileInfo) error) error { - if !b.Cache.canBeCached(t) { - return b.Backend.List(ctx, t, fn) - } - - // will contain the IDs of the files that are in the repository - ids := restic.NewIDSet() - - // wrap the original function to also add the file to the ids set - wrapFn := func(f backend.FileInfo) error { - id, err := restic.ParseID(f.Name) - if err != nil { - // ignore files with invalid name - return nil - } - - ids.Insert(id) - - // execute the original function - return fn(f) - } - - err := b.Backend.List(ctx, t, wrapFn) - if err != nil { - return err - } - - if ctx.Err() != nil { - return ctx.Err() - } - - // clear the cache for files that are not in the repo anymore, ignore errors - err = b.Cache.Clear(t, ids) - if err != nil { - fmt.Fprintf(os.Stderr, "error clearing %s files in cache: %v\n", t.String(), err) - } - - return nil -} diff --git a/mover-restic/restic/internal/backend/cache/backend_test.go b/mover-restic/restic/internal/backend/cache/backend_test.go index 7f83e40cb..7addc275d 100644 --- a/mover-restic/restic/internal/backend/cache/backend_test.go +++ b/mover-restic/restic/internal/backend/cache/backend_test.go @@ -57,13 +57,6 @@ func randomData(n int) (backend.Handle, []byte) { return h, data } -func list(t testing.TB, be backend.Backend, fn func(backend.FileInfo) error) { - err := be.List(context.TODO(), backend.IndexFile, fn) - if err != nil { - t.Fatal(err) - } -} - func TestBackend(t *testing.T) { be := mem.New() c := TestNewCache(t) @@ -245,71 +238,3 @@ func TestErrorBackend(t *testing.T) { wg.Wait() } - -func TestAutomaticCacheClear(t *testing.T) { - be := mem.New() - c := TestNewCache(t) - wbe := c.Wrap(be) - - // add two handles h1 and h2 - h1, data := randomData(2000) - // save h1 directly to the backend - save(t, be, h1, data) - if c.Has(h1) { - t.Errorf("cache has file1 too early") - } - - h2, data2 := randomData(3000) - - // save h2 directly to the backend - save(t, be, h2, data2) - if c.Has(h2) { - t.Errorf("cache has file2 too early") - } - - loadAndCompare(t, wbe, h1, data) - if !c.Has(h1) { - t.Errorf("cache doesn't have file1 after load") - } - - loadAndCompare(t, wbe, h2, data2) - if !c.Has(h2) { - t.Errorf("cache doesn't have file2 after load") - } - - // remove h1 directly from the backend - remove(t, be, h1) - if !c.Has(h1) { - t.Errorf("file1 not in cache any more, should be removed from cache only after list") - } - - // list all files in the backend - list(t, wbe, func(_ backend.FileInfo) error { return nil }) - - // h1 should be removed from the cache - if c.Has(h1) { - t.Errorf("cache has file1 after remove") - } - - // h2 should still be in the cache - if !c.Has(h2) { - t.Errorf("cache doesn't have file2 after list") - } -} - -func TestAutomaticCacheClearInvalidFilename(t *testing.T) { - be := mem.New() - c := TestNewCache(t) - - data := test.Random(rand.Int(), 42) - h := backend.Handle{ - Type: backend.IndexFile, - Name: "tmp12345", - } - save(t, be, h, data) - - wbe := c.Wrap(be) - - // list all files in the backend - list(t, wbe, func(_ backend.FileInfo) error { return nil }) -} diff --git a/mover-restic/restic/internal/backend/http_transport.go b/mover-restic/restic/internal/backend/http_transport.go index 5a3856e41..5162d3571 100644 --- a/mover-restic/restic/internal/backend/http_transport.go +++ b/mover-restic/restic/internal/backend/http_transport.go @@ -31,9 +31,6 @@ type TransportOptions struct { // Specify Custom User-Agent for the http Client HTTPUserAgent string - - // Timeout after which to retry stuck requests - StuckRequestTimeout time.Duration } // readPEMCertKey reads a file and returns the PEM encoded certificate and key @@ -146,11 +143,7 @@ func Transport(opts TransportOptions) (http.RoundTripper, error) { } if feature.Flag.Enabled(feature.BackendErrorRedesign) { - if opts.StuckRequestTimeout == 0 { - opts.StuckRequestTimeout = 5 * time.Minute - } - - rt = newWatchdogRoundtripper(rt, opts.StuckRequestTimeout, 128*1024) + rt = newWatchdogRoundtripper(rt, 5*time.Minute, 128*1024) } // wrap in the debug round tripper (if active) diff --git a/mover-restic/restic/internal/backend/rest/rest.go b/mover-restic/restic/internal/backend/rest/rest.go index d0a08175b..1af88ec3f 100644 --- a/mover-restic/restic/internal/backend/rest/rest.go +++ b/mover-restic/restic/internal/backend/rest/rest.go @@ -143,12 +143,6 @@ func (b *Backend) Save(ctx context.Context, h backend.Handle, rd backend.RewindR if err != nil { return errors.WithStack(err) } - req.GetBody = func() (io.ReadCloser, error) { - if err := rd.Rewind(); err != nil { - return nil, err - } - return io.NopCloser(rd), nil - } req.Header.Set("Content-Type", "application/octet-stream") req.Header.Set("Accept", ContentTypeV2) diff --git a/mover-restic/restic/internal/backend/retry/backend_retry.go b/mover-restic/restic/internal/backend/retry/backend_retry.go index 92c285c4b..8d0f42bfd 100644 --- a/mover-restic/restic/internal/backend/retry/backend_retry.go +++ b/mover-restic/restic/internal/backend/retry/backend_retry.go @@ -209,10 +209,9 @@ func (be *Backend) Load(ctx context.Context, h backend.Handle, length int, offse return be.Backend.Load(ctx, h, length, offset, consumer) }) - if feature.Flag.Enabled(feature.BackendErrorRedesign) && err != nil && ctx.Err() == nil && !be.IsPermanentError(err) { + if feature.Flag.Enabled(feature.BackendErrorRedesign) && err != nil && !be.IsPermanentError(err) { // We've exhausted the retries, the file is likely inaccessible. By excluding permanent - // errors, not found or truncated files are not recorded. Also ignore errors if the context - // was canceled. + // errors, not found or truncated files are not recorded. be.failedLoads.LoadOrStore(key, time.Now()) } diff --git a/mover-restic/restic/internal/backend/retry/backend_retry_test.go b/mover-restic/restic/internal/backend/retry/backend_retry_test.go index ffb8ae186..fd76200d4 100644 --- a/mover-restic/restic/internal/backend/retry/backend_retry_test.go +++ b/mover-restic/restic/internal/backend/retry/backend_retry_test.go @@ -357,30 +357,6 @@ func TestBackendLoadCircuitBreaker(t *testing.T) { test.Equals(t, notFound, err, "expected circuit breaker to reset, got %v") } -func TestBackendLoadCircuitBreakerCancel(t *testing.T) { - cctx, cancel := context.WithCancel(context.Background()) - be := mock.NewBackend() - be.OpenReaderFn = func(ctx context.Context, h backend.Handle, length int, offset int64) (io.ReadCloser, error) { - cancel() - return nil, errors.New("something") - } - nilRd := func(rd io.Reader) (err error) { - return nil - } - - TestFastRetries(t) - retryBackend := New(be, 2, nil, nil) - // canceling the context should not trip the circuit breaker - err := retryBackend.Load(cctx, backend.Handle{Name: "other"}, 0, 0, nilRd) - test.Equals(t, context.Canceled, err, "unexpected error") - - // reset context and check that the cirucit breaker does not return an error - cctx, cancel = context.WithCancel(context.Background()) - defer cancel() - err = retryBackend.Load(cctx, backend.Handle{Name: "other"}, 0, 0, nilRd) - test.Equals(t, context.Canceled, err, "unexpected error") -} - func TestBackendStatNotExists(t *testing.T) { // stat should not retry if the error matches IsNotExist notFound := errors.New("not found") diff --git a/mover-restic/restic/internal/backend/sftp/sftp.go b/mover-restic/restic/internal/backend/sftp/sftp.go index efbd0c8d5..70fc30a62 100644 --- a/mover-restic/restic/internal/backend/sftp/sftp.go +++ b/mover-restic/restic/internal/backend/sftp/sftp.go @@ -578,10 +578,6 @@ func (r *SFTP) deleteRecursive(ctx context.Context, name string) error { } for _, fi := range entries { - if ctx.Err() != nil { - return ctx.Err() - } - itemName := r.Join(name, fi.Name()) if fi.IsDir() { err := r.deleteRecursive(ctx, itemName) diff --git a/mover-restic/restic/internal/backend/watchdog_roundtriper.go b/mover-restic/restic/internal/backend/watchdog_roundtriper.go index dc270b974..e3e10d7fe 100644 --- a/mover-restic/restic/internal/backend/watchdog_roundtriper.go +++ b/mover-restic/restic/internal/backend/watchdog_roundtriper.go @@ -65,9 +65,6 @@ func (w *watchdogRoundtripper) RoundTrip(req *http.Request) (*http.Response, err resp, err := w.rt.RoundTrip(req) if err != nil { - if isTimeout(err) { - err = errRequestTimeout - } return nil, err } diff --git a/mover-restic/restic/internal/backend/watchdog_roundtriper_test.go b/mover-restic/restic/internal/backend/watchdog_roundtriper_test.go index f7f90259c..bc43447e1 100644 --- a/mover-restic/restic/internal/backend/watchdog_roundtriper_test.go +++ b/mover-restic/restic/internal/backend/watchdog_roundtriper_test.go @@ -135,7 +135,7 @@ func TestUploadTimeout(t *testing.T) { rtest.OK(t, err) resp, err := rt.RoundTrip(req) - rtest.Equals(t, errRequestTimeout, err) + rtest.Equals(t, context.Canceled, err) // make linter happy if resp != nil { rtest.OK(t, resp.Body.Close()) @@ -162,7 +162,7 @@ func TestProcessingTimeout(t *testing.T) { rtest.OK(t, err) resp, err := rt.RoundTrip(req) - rtest.Equals(t, errRequestTimeout, err) + rtest.Equals(t, context.Canceled, err) // make linter happy if resp != nil { rtest.OK(t, resp.Body.Close()) @@ -190,7 +190,7 @@ func TestDownloadTimeout(t *testing.T) { })) defer srv.Close() - rt := newWatchdogRoundtripper(http.DefaultTransport, 25*time.Millisecond, 1024) + rt := newWatchdogRoundtripper(http.DefaultTransport, 10*time.Millisecond, 1024) req, err := http.NewRequestWithContext(context.TODO(), "GET", srv.URL, io.NopCloser(bytes.NewReader(msg))) rtest.OK(t, err) diff --git a/mover-restic/restic/internal/fs/ea_windows.go b/mover-restic/restic/internal/fs/ea_windows.go index bf7b02fd4..08466c33f 100644 --- a/mover-restic/restic/internal/fs/ea_windows.go +++ b/mover-restic/restic/internal/fs/ea_windows.go @@ -8,7 +8,6 @@ import ( "encoding/binary" "errors" "fmt" - "strings" "syscall" "unsafe" @@ -284,35 +283,3 @@ func setFileEA(handle windows.Handle, iosb *ioStatusBlock, buf *uint8, bufLen ui status = ntStatus(r0) return } - -// PathSupportsExtendedAttributes returns true if the path supports extended attributes. -func PathSupportsExtendedAttributes(path string) (supported bool, err error) { - var fileSystemFlags uint32 - utf16Path, err := windows.UTF16PtrFromString(path) - if err != nil { - return false, err - } - err = windows.GetVolumeInformation(utf16Path, nil, 0, nil, nil, &fileSystemFlags, nil, 0) - if err != nil { - return false, err - } - supported = (fileSystemFlags & windows.FILE_SUPPORTS_EXTENDED_ATTRIBUTES) != 0 - return supported, nil -} - -// GetVolumePathName returns the volume path name for the given path. -func GetVolumePathName(path string) (volumeName string, err error) { - utf16Path, err := windows.UTF16PtrFromString(path) - if err != nil { - return "", err - } - // Get the volume path (e.g., "D:") - var volumePath [windows.MAX_PATH + 1]uint16 - err = windows.GetVolumePathName(utf16Path, &volumePath[0], windows.MAX_PATH+1) - if err != nil { - return "", err - } - // Trim any trailing backslashes - volumeName = strings.TrimRight(windows.UTF16ToString(volumePath[:]), "\\") - return volumeName, nil -} diff --git a/mover-restic/restic/internal/fs/ea_windows_test.go b/mover-restic/restic/internal/fs/ea_windows_test.go index 74afd7aa5..b249f43c4 100644 --- a/mover-restic/restic/internal/fs/ea_windows_test.go +++ b/mover-restic/restic/internal/fs/ea_windows_test.go @@ -10,7 +10,6 @@ import ( "os" "path/filepath" "reflect" - "strings" "syscall" "testing" "unsafe" @@ -246,78 +245,3 @@ func testSetGetEA(t *testing.T, path string, handle windows.Handle, testEAs []Ex t.Fatalf("EAs read from path %s don't match", path) } } - -func TestPathSupportsExtendedAttributes(t *testing.T) { - testCases := []struct { - name string - path string - expected bool - }{ - { - name: "System drive", - path: os.Getenv("SystemDrive") + `\`, - expected: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - supported, err := PathSupportsExtendedAttributes(tc.path) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if supported != tc.expected { - t.Errorf("Expected %v, got %v for path %s", tc.expected, supported, tc.path) - } - }) - } - - // Test with an invalid path - _, err := PathSupportsExtendedAttributes("Z:\\NonExistentPath-UAS664da5s4dyu56das45f5as") - if err == nil { - t.Error("Expected an error for non-existent path, but got nil") - } -} - -func TestGetVolumePathName(t *testing.T) { - tempDirVolume := filepath.VolumeName(os.TempDir()) - testCases := []struct { - name string - path string - expectedPrefix string - }{ - { - name: "Root directory", - path: os.Getenv("SystemDrive") + `\`, - expectedPrefix: os.Getenv("SystemDrive"), - }, - { - name: "Nested directory", - path: os.Getenv("SystemDrive") + `\Windows\System32`, - expectedPrefix: os.Getenv("SystemDrive"), - }, - { - name: "Temp directory", - path: os.TempDir() + `\`, - expectedPrefix: tempDirVolume, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - volumeName, err := GetVolumePathName(tc.path) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if !strings.HasPrefix(volumeName, tc.expectedPrefix) { - t.Errorf("Expected volume name to start with %s, but got %s", tc.expectedPrefix, volumeName) - } - }) - } - - // Test with an invalid path - _, err := GetVolumePathName("Z:\\NonExistentPath") - if err == nil { - t.Error("Expected an error for non-existent path, but got nil") - } -} diff --git a/mover-restic/restic/internal/fs/file.go b/mover-restic/restic/internal/fs/file.go index 85b202dc8..929195f1c 100644 --- a/mover-restic/restic/internal/fs/file.go +++ b/mover-restic/restic/internal/fs/file.go @@ -134,7 +134,7 @@ func IsAccessDenied(err error) bool { // ResetPermissions resets the permissions of the file at the specified path func ResetPermissions(path string) error { // Set the default file permissions - if err := os.Chmod(fixpath(path), 0600); err != nil { + if err := os.Chmod(path, 0600); err != nil { return err } return nil diff --git a/mover-restic/restic/internal/fs/file_windows.go b/mover-restic/restic/internal/fs/file_windows.go index 50c7e9938..b05068c42 100644 --- a/mover-restic/restic/internal/fs/file_windows.go +++ b/mover-restic/restic/internal/fs/file_windows.go @@ -85,7 +85,7 @@ func ClearSystem(path string) error { // ClearAttribute removes the specified attribute from the file. func ClearAttribute(path string, attribute uint32) error { - ptr, err := windows.UTF16PtrFromString(fixpath(path)) + ptr, err := windows.UTF16PtrFromString(path) if err != nil { return err } diff --git a/mover-restic/restic/internal/fs/fs_reader_command.go b/mover-restic/restic/internal/fs/fs_reader_command.go index 6d061f641..3830e5811 100644 --- a/mover-restic/restic/internal/fs/fs_reader_command.go +++ b/mover-restic/restic/internal/fs/fs_reader_command.go @@ -29,10 +29,6 @@ type CommandReader struct { } func NewCommandReader(ctx context.Context, args []string, logOutput io.Writer) (*CommandReader, error) { - if len(args) == 0 { - return nil, fmt.Errorf("no command was specified as argument") - } - // Prepare command and stdout command := exec.CommandContext(ctx, args[0], args[1:]...) stdout, err := command.StdoutPipe() diff --git a/mover-restic/restic/internal/fs/fs_reader_command_test.go b/mover-restic/restic/internal/fs/fs_reader_command_test.go index 8f0d17b1e..a9028544c 100644 --- a/mover-restic/restic/internal/fs/fs_reader_command_test.go +++ b/mover-restic/restic/internal/fs/fs_reader_command_test.go @@ -34,11 +34,6 @@ func TestCommandReaderInvalid(t *testing.T) { test.Assert(t, err != nil, "missing error") } -func TestCommandReaderEmptyArgs(t *testing.T) { - _, err := fs.NewCommandReader(context.TODO(), []string{}, io.Discard) - test.Assert(t, err != nil, "missing error") -} - func TestCommandReaderOutput(t *testing.T) { reader, err := fs.NewCommandReader(context.TODO(), []string{"echo", "hello world"}, io.Discard) test.OK(t, err) diff --git a/mover-restic/restic/internal/fs/sd_windows.go b/mover-restic/restic/internal/fs/sd_windows.go index 0004f1809..5d98b4ef4 100644 --- a/mover-restic/restic/internal/fs/sd_windows.go +++ b/mover-restic/restic/internal/fs/sd_windows.go @@ -11,7 +11,6 @@ import ( "unsafe" "github.com/restic/restic/internal/debug" - "github.com/restic/restic/internal/errors" "golang.org/x/sys/windows" ) @@ -48,20 +47,19 @@ func GetSecurityDescriptor(filePath string) (securityDescriptor *[]byte, err err var sd *windows.SECURITY_DESCRIPTOR - // store original value to avoid unrelated changes in the error check - useLowerPrivileges := lowerPrivileges.Load() - if useLowerPrivileges { + if lowerPrivileges.Load() { sd, err = getNamedSecurityInfoLow(filePath) } else { sd, err = getNamedSecurityInfoHigh(filePath) } if err != nil { - if !useLowerPrivileges && isHandlePrivilegeNotHeldError(err) { + if !lowerPrivileges.Load() && isHandlePrivilegeNotHeldError(err) { // If ERROR_PRIVILEGE_NOT_HELD is encountered, fallback to backups/restores using lower non-admin privileges. lowerPrivileges.Store(true) - return GetSecurityDescriptor(filePath) - } else if errors.Is(err, windows.ERROR_NOT_SUPPORTED) { - return nil, nil + sd, err = getNamedSecurityInfoLow(filePath) + if err != nil { + return nil, fmt.Errorf("get low-level named security info failed with: %w", err) + } } else { return nil, fmt.Errorf("get named security info failed with: %w", err) } @@ -108,19 +106,20 @@ func SetSecurityDescriptor(filePath string, securityDescriptor *[]byte) error { sacl = nil } - // store original value to avoid unrelated changes in the error check - useLowerPrivileges := lowerPrivileges.Load() - if useLowerPrivileges { + if lowerPrivileges.Load() { err = setNamedSecurityInfoLow(filePath, dacl) } else { err = setNamedSecurityInfoHigh(filePath, owner, group, dacl, sacl) } if err != nil { - if !useLowerPrivileges && isHandlePrivilegeNotHeldError(err) { + if !lowerPrivileges.Load() && isHandlePrivilegeNotHeldError(err) { // If ERROR_PRIVILEGE_NOT_HELD is encountered, fallback to backups/restores using lower non-admin privileges. lowerPrivileges.Store(true) - return SetSecurityDescriptor(filePath, securityDescriptor) + err = setNamedSecurityInfoLow(filePath, dacl) + if err != nil { + return fmt.Errorf("set low-level named security info failed with: %w", err) + } } else { return fmt.Errorf("set named security info failed with: %w", err) } @@ -130,22 +129,22 @@ func SetSecurityDescriptor(filePath string, securityDescriptor *[]byte) error { // getNamedSecurityInfoHigh gets the higher level SecurityDescriptor which requires admin permissions. func getNamedSecurityInfoHigh(filePath string) (*windows.SECURITY_DESCRIPTOR, error) { - return windows.GetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, highSecurityFlags) + return windows.GetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, highSecurityFlags) } // getNamedSecurityInfoLow gets the lower level SecurityDescriptor which requires no admin permissions. func getNamedSecurityInfoLow(filePath string) (*windows.SECURITY_DESCRIPTOR, error) { - return windows.GetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, lowBackupSecurityFlags) + return windows.GetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, lowBackupSecurityFlags) } // setNamedSecurityInfoHigh sets the higher level SecurityDescriptor which requires admin permissions. func setNamedSecurityInfoHigh(filePath string, owner *windows.SID, group *windows.SID, dacl *windows.ACL, sacl *windows.ACL) error { - return windows.SetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, highSecurityFlags, owner, group, dacl, sacl) + return windows.SetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, highSecurityFlags, owner, group, dacl, sacl) } // setNamedSecurityInfoLow sets the lower level SecurityDescriptor which requires no admin permissions. func setNamedSecurityInfoLow(filePath string, dacl *windows.ACL) error { - return windows.SetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, lowRestoreSecurityFlags, nil, nil, dacl, nil) + return windows.SetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, lowRestoreSecurityFlags, nil, nil, dacl, nil) } // enableBackupPrivilege enables privilege for backing up security descriptors diff --git a/mover-restic/restic/internal/fuse/dir.go b/mover-restic/restic/internal/fuse/dir.go index fd030295b..763a9640c 100644 --- a/mover-restic/restic/internal/fuse/dir.go +++ b/mover-restic/restic/internal/fuse/dir.go @@ -107,10 +107,6 @@ func (d *dir) open(ctx context.Context) error { } items := make(map[string]*restic.Node) for _, n := range tree.Nodes { - if ctx.Err() != nil { - return ctx.Err() - } - nodes, err := replaceSpecialNodes(ctx, d.root.repo, n) if err != nil { debug.Log(" replaceSpecialNodes(%v) failed: %v", n, err) @@ -175,10 +171,6 @@ func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { }) for _, node := range d.items { - if ctx.Err() != nil { - return nil, ctx.Err() - } - name := cleanupNodeName(node.Name) var typ fuse.DirentType switch node.Type { diff --git a/mover-restic/restic/internal/fuse/file.go b/mover-restic/restic/internal/fuse/file.go index 494fca283..e2e0cf9a0 100644 --- a/mover-restic/restic/internal/fuse/file.go +++ b/mover-restic/restic/internal/fuse/file.go @@ -66,16 +66,12 @@ func (f *file) Attr(_ context.Context, a *fuse.Attr) error { } -func (f *file) Open(ctx context.Context, _ *fuse.OpenRequest, _ *fuse.OpenResponse) (fs.Handle, error) { +func (f *file) Open(_ context.Context, _ *fuse.OpenRequest, _ *fuse.OpenResponse) (fs.Handle, error) { debug.Log("open file %v with %d blobs", f.node.Name, len(f.node.Content)) var bytes uint64 cumsize := make([]uint64, 1+len(f.node.Content)) for i, id := range f.node.Content { - if ctx.Err() != nil { - return nil, ctx.Err() - } - size, found := f.root.repo.LookupBlobSize(restic.DataBlob, id) if !found { return nil, errors.Errorf("id %v not found in repository", id) diff --git a/mover-restic/restic/internal/fuse/snapshots_dir.go b/mover-restic/restic/internal/fuse/snapshots_dir.go index 4cae7106c..7369ea17a 100644 --- a/mover-restic/restic/internal/fuse/snapshots_dir.go +++ b/mover-restic/restic/internal/fuse/snapshots_dir.go @@ -78,10 +78,6 @@ func (d *SnapshotsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { } for name, entry := range meta.names { - if ctx.Err() != nil { - return nil, ctx.Err() - } - d := fuse.Dirent{ Inode: inodeFromName(d.inode, name), Name: name, diff --git a/mover-restic/restic/internal/repository/check.go b/mover-restic/restic/internal/repository/check.go index 0a48f2b9d..9f571cb4f 100644 --- a/mover-restic/restic/internal/repository/check.go +++ b/mover-restic/restic/internal/repository/check.go @@ -95,10 +95,6 @@ func checkPackInner(ctx context.Context, r *Repository, id restic.ID, blobs []re it := newPackBlobIterator(id, newBufReader(bufRd), 0, blobs, r.Key(), dec) for { - if ctx.Err() != nil { - return ctx.Err() - } - val, err := it.Next() if err == errPackEOF { break diff --git a/mover-restic/restic/internal/repository/index/master_index.go b/mover-restic/restic/internal/repository/index/master_index.go index 9b5c4f9f8..f8e776b23 100644 --- a/mover-restic/restic/internal/repository/index/master_index.go +++ b/mover-restic/restic/internal/repository/index/master_index.go @@ -456,9 +456,6 @@ func (mi *MasterIndex) Rewrite(ctx context.Context, repo restic.Unpacked, exclud worker := func() error { for idx := range saveCh { idx.Finalize() - if len(idx.packs) == 0 { - continue - } if _, err := idx.SaveIndex(wgCtx, repo); err != nil { return err } diff --git a/mover-restic/restic/internal/repository/repository.go b/mover-restic/restic/internal/repository/repository.go index d408e3105..838858c38 100644 --- a/mover-restic/restic/internal/repository/repository.go +++ b/mover-restic/restic/internal/repository/repository.go @@ -706,10 +706,19 @@ func (r *Repository) prepareCache() error { return nil } + indexIDs := r.idx.IDs() + debug.Log("prepare cache with %d index files", len(indexIDs)) + + // clear old index files + err := r.Cache.Clear(restic.IndexFile, indexIDs) + if err != nil { + fmt.Fprintf(os.Stderr, "error clearing index files in cache: %v\n", err) + } + packs := r.idx.Packs(restic.NewIDSet()) // clear old packs - err := r.Cache.Clear(restic.PackFile, packs) + err = r.Cache.Clear(restic.PackFile, packs) if err != nil { fmt.Fprintf(os.Stderr, "error clearing pack files in cache: %v\n", err) } @@ -991,10 +1000,6 @@ func streamPackPart(ctx context.Context, beLoad backendLoadFn, loadBlobFn loadBl it := newPackBlobIterator(packID, newByteReader(data), dataStart, blobs, key, dec) for { - if ctx.Err() != nil { - return ctx.Err() - } - val, err := it.Next() if err == errPackEOF { break diff --git a/mover-restic/restic/internal/restic/lock.go b/mover-restic/restic/internal/restic/lock.go index 969d0593d..49c7cedf2 100644 --- a/mover-restic/restic/internal/restic/lock.go +++ b/mover-restic/restic/internal/restic/lock.go @@ -103,14 +103,10 @@ func NewExclusiveLock(ctx context.Context, repo Unpacked) (*Lock, error) { var waitBeforeLockCheck = 200 * time.Millisecond -// delay increases by factor 2 on each retry -var initialWaitBetweenLockRetries = 5 * time.Second - // TestSetLockTimeout can be used to reduce the lock wait timeout for tests. func TestSetLockTimeout(t testing.TB, d time.Duration) { t.Logf("setting lock timeout to %v", d) waitBeforeLockCheck = d - initialWaitBetweenLockRetries = d } func newLock(ctx context.Context, repo Unpacked, excl bool) (*Lock, error) { @@ -174,17 +170,8 @@ func (l *Lock) checkForOtherLocks(ctx context.Context) error { if l.lockID != nil { checkedIDs.Insert(*l.lockID) } - delay := initialWaitBetweenLockRetries // retry locking a few times - for i := 0; i < 4; i++ { - if i != 0 { - // sleep between retries to give backend some time to settle - if err := cancelableDelay(ctx, delay); err != nil { - return err - } - delay *= 2 - } - + for i := 0; i < 3; i++ { // Store updates in new IDSet to prevent data races var m sync.Mutex newCheckedIDs := NewIDSet(checkedIDs.List()...) @@ -226,18 +213,6 @@ func (l *Lock) checkForOtherLocks(ctx context.Context) error { return err } -func cancelableDelay(ctx context.Context, delay time.Duration) error { - // delay next try a bit - timer := time.NewTimer(delay) - select { - case <-ctx.Done(): - timer.Stop() - return ctx.Err() - case <-timer.C: - } - return nil -} - // createLock acquires the lock by creating a file in the repository. func (l *Lock) createLock(ctx context.Context) (ID, error) { id, err := SaveJSONUnpacked(ctx, l.repo, LockFile, l) diff --git a/mover-restic/restic/internal/restic/node.go b/mover-restic/restic/internal/restic/node.go index 6afdff64a..51c6071b7 100644 --- a/mover-restic/restic/internal/restic/node.go +++ b/mover-restic/restic/internal/restic/node.go @@ -229,13 +229,6 @@ func (node *Node) CreateAt(ctx context.Context, path string, repo BlobLoader) er func (node Node) RestoreMetadata(path string, warn func(msg string)) error { err := node.restoreMetadata(path, warn) if err != nil { - // It is common to have permission errors for folders like /home - // unless you're running as root, so ignore those. - if os.Geteuid() > 0 && errors.Is(err, os.ErrPermission) { - debug.Log("not running as root, ignoring permission error for %v: %v", - path, err) - return nil - } debug.Log("restoreMetadata(%s) error %v", path, err) } @@ -246,26 +239,33 @@ func (node Node) restoreMetadata(path string, warn func(msg string)) error { var firsterr error if err := lchown(path, int(node.UID), int(node.GID)); err != nil { - firsterr = errors.WithStack(err) + // Like "cp -a" and "rsync -a" do, we only report lchown permission errors + // if we run as root. + if os.Geteuid() > 0 && os.IsPermission(err) { + debug.Log("not running as root, ignoring lchown permission error for %v: %v", + path, err) + } else { + firsterr = errors.WithStack(err) + } } - if err := node.restoreExtendedAttributes(path); err != nil { - debug.Log("error restoring extended attributes for %v: %v", path, err) - if firsterr == nil { + if err := node.RestoreTimestamps(path); err != nil { + debug.Log("error restoring timestamps for dir %v: %v", path, err) + if firsterr != nil { firsterr = err } } - if err := node.restoreGenericAttributes(path, warn); err != nil { - debug.Log("error restoring generic attributes for %v: %v", path, err) - if firsterr == nil { + if err := node.restoreExtendedAttributes(path); err != nil { + debug.Log("error restoring extended attributes for %v: %v", path, err) + if firsterr != nil { firsterr = err } } - if err := node.RestoreTimestamps(path); err != nil { - debug.Log("error restoring timestamps for %v: %v", path, err) - if firsterr == nil { + if err := node.restoreGenericAttributes(path, warn); err != nil { + debug.Log("error restoring generic attributes for %v: %v", path, err) + if firsterr != nil { firsterr = err } } @@ -275,7 +275,7 @@ func (node Node) restoreMetadata(path string, warn func(msg string)) error { // calls above would fail. if node.Type != "symlink" { if err := fs.Chmod(path, node.Mode); err != nil { - if firsterr == nil { + if firsterr != nil { firsterr = errors.WithStack(err) } } diff --git a/mover-restic/restic/internal/restic/node_test.go b/mover-restic/restic/internal/restic/node_test.go index ab7f66e5b..6e0f31e21 100644 --- a/mover-restic/restic/internal/restic/node_test.go +++ b/mover-restic/restic/internal/restic/node_test.go @@ -13,7 +13,6 @@ import ( "time" "github.com/google/go-cmp/cmp" - "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/test" rtest "github.com/restic/restic/internal/test" ) @@ -197,20 +196,6 @@ var nodeTests = []Node{ {"user.foo", []byte("bar")}, }, }, - { - Name: "testXattrFileMacOSResourceFork", - Type: "file", - Content: IDs{}, - UID: uint32(os.Getuid()), - GID: uint32(os.Getgid()), - Mode: 0604, - ModTime: parseTime("2005-05-14 21:07:03.111"), - AccessTime: parseTime("2005-05-14 21:07:04.222"), - ChangeTime: parseTime("2005-05-14 21:07:05.333"), - ExtendedAttributes: []ExtendedAttribute{ - {"com.apple.ResourceFork", []byte("bar")}, - }, - }, } func TestNodeRestoreAt(t *testing.T) { @@ -230,11 +215,6 @@ func TestNodeRestoreAt(t *testing.T) { extAttrArr[i].Name = strings.ToUpper(extAttrArr[i].Name) } } - for _, attr := range test.ExtendedAttributes { - if strings.HasPrefix(attr.Name, "com.apple.") && runtime.GOOS != "darwin" { - t.Skipf("attr %v only relevant on macOS", attr.Name) - } - } // tempdir might be backed by a filesystem that does not support // extended attributes @@ -248,6 +228,10 @@ func TestNodeRestoreAt(t *testing.T) { rtest.OK(t, test.CreateAt(context.TODO(), nodePath, nil)) rtest.OK(t, test.RestoreMetadata(nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) })) + if test.Type == "dir" { + rtest.OK(t, test.RestoreTimestamps(nodePath)) + } + fi, err := os.Lstat(nodePath) rtest.OK(t, err) @@ -398,14 +382,3 @@ func TestSymlinkSerializationFormat(t *testing.T) { test.Assert(t, n2.LinkTargetRaw == nil, "quoted link target is just a helper field and must be unset after decoding") } } - -func TestNodeRestoreMetadataError(t *testing.T) { - tempdir := t.TempDir() - - node := nodeTests[0] - nodePath := filepath.Join(tempdir, node.Name) - - // This will fail because the target file does not exist - err := node.RestoreMetadata(nodePath, func(msg string) { rtest.OK(t, fmt.Errorf("Warning triggered for path: %s: %s", nodePath, msg)) }) - test.Assert(t, errors.Is(err, os.ErrNotExist), "failed for an unexpected reason") -} diff --git a/mover-restic/restic/internal/restic/node_windows.go b/mover-restic/restic/internal/restic/node_windows.go index bce01ccad..2785e0412 100644 --- a/mover-restic/restic/internal/restic/node_windows.go +++ b/mover-restic/restic/internal/restic/node_windows.go @@ -8,7 +8,6 @@ import ( "reflect" "runtime" "strings" - "sync" "syscall" "unsafe" @@ -33,16 +32,6 @@ var ( modAdvapi32 = syscall.NewLazyDLL("advapi32.dll") procEncryptFile = modAdvapi32.NewProc("EncryptFileW") procDecryptFile = modAdvapi32.NewProc("DecryptFileW") - - // eaSupportedVolumesMap is a map of volumes to boolean values indicating if they support extended attributes. - eaSupportedVolumesMap = sync.Map{} -) - -const ( - extendedPathPrefix = `\\?\` - uncPathPrefix = `\\?\UNC\` - globalRootPrefix = `\\?\GLOBALROOT\` - volumeGUIDPrefix = `\\?\Volume{` ) // mknod is not supported on Windows. @@ -362,137 +351,32 @@ func decryptFile(pathPointer *uint16) error { } // fillGenericAttributes fills in the generic attributes for windows like File Attributes, -// Created time and Security Descriptors. -// It also checks if the volume supports extended attributes and stores the result in a map -// so that it does not have to be checked again for subsequent calls for paths in the same volume. +// Created time etc. func (node *Node) fillGenericAttributes(path string, fi os.FileInfo, stat *statT) (allowExtended bool, err error) { if strings.Contains(filepath.Base(path), ":") { - // Do not process for Alternate Data Streams in Windows + //Do not process for Alternate Data Streams in Windows // Also do not allow processing of extended attributes for ADS. return false, nil } - - if strings.HasSuffix(filepath.Clean(path), `\`) { - // filepath.Clean(path) ends with '\' for Windows root volume paths only - // Do not process file attributes, created time and sd for windows root volume paths - // Security descriptors are not supported for root volume paths. - // Though file attributes and created time are supported for root volume paths, - // we ignore them and we do not want to replace them during every restore. - allowExtended, err = checkAndStoreEASupport(path) - if err != nil { - return false, err - } - return allowExtended, nil - } - - var sd *[]byte - if node.Type == "file" || node.Type == "dir" { - // Check EA support and get security descriptor for file/dir only - allowExtended, err = checkAndStoreEASupport(path) - if err != nil { - return false, err - } - if sd, err = fs.GetSecurityDescriptor(path); err != nil { - return allowExtended, err - } - } - // Add Windows attributes - node.GenericAttributes, err = WindowsAttrsToGenericAttributes(WindowsAttributes{ - CreationTime: getCreationTime(fi, path), - FileAttributes: &stat.FileAttributes, - SecurityDescriptor: sd, - }) - return allowExtended, err -} - -// checkAndStoreEASupport checks if the volume of the path supports extended attributes and stores the result in a map -// If the result is already in the map, it returns the result from the map. -func checkAndStoreEASupport(path string) (isEASupportedVolume bool, err error) { - var volumeName string - volumeName, err = prepareVolumeName(path) - if err != nil { - return false, err - } - - if volumeName != "" { - // First check if the manually prepared volume name is already in the map - eaSupportedValue, exists := eaSupportedVolumesMap.Load(volumeName) - if exists { - // Cache hit, immediately return the cached value - return eaSupportedValue.(bool), nil - } - // If not found, check if EA is supported with manually prepared volume name - isEASupportedVolume, err = fs.PathSupportsExtendedAttributes(volumeName + `\`) - // If the prepared volume name is not valid, we will fetch the actual volume name next. - if err != nil && !errors.Is(err, windows.DNS_ERROR_INVALID_NAME) { - debug.Log("Error checking if extended attributes are supported for prepared volume name %s: %v", volumeName, err) - // There can be multiple errors like path does not exist, bad network path, etc. - // We just gracefully disallow extended attributes for cases. - return false, nil - } - } - // If an entry is not found, get the actual volume name using the GetVolumePathName function - volumeNameActual, err := fs.GetVolumePathName(path) - if err != nil { - debug.Log("Error getting actual volume name %s for path %s: %v", volumeName, path, err) - // There can be multiple errors like path does not exist, bad network path, etc. - // We just gracefully disallow extended attributes for cases. - return false, nil - } - if volumeNameActual != volumeName { - // If the actual volume name is different, check cache for the actual volume name - eaSupportedValue, exists := eaSupportedVolumesMap.Load(volumeNameActual) - if exists { - // Cache hit, immediately return the cached value - return eaSupportedValue.(bool), nil - } - // If the actual volume name is different and is not in the map, again check if the new volume supports extended attributes with the actual volume name - isEASupportedVolume, err = fs.PathSupportsExtendedAttributes(volumeNameActual + `\`) - // Debug log for cases where the prepared volume name is not valid - if err != nil { - debug.Log("Error checking if extended attributes are supported for actual volume name %s: %v", volumeNameActual, err) - // There can be multiple errors like path does not exist, bad network path, etc. - // We just gracefully disallow extended attributes for cases. - return false, nil - } else { - debug.Log("Checking extended attributes. Prepared volume name: %s, actual volume name: %s, isEASupportedVolume: %v, err: %v", volumeName, volumeNameActual, isEASupportedVolume, err) - } - } - if volumeNameActual != "" { - eaSupportedVolumesMap.Store(volumeNameActual, isEASupportedVolume) - } - return isEASupportedVolume, err -} - -// prepareVolumeName prepares the volume name for different cases in Windows -func prepareVolumeName(path string) (volumeName string, err error) { - // Check if it's an extended length path - if strings.HasPrefix(path, globalRootPrefix) { - // Extract the VSS snapshot volume name eg. `\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopyXX` - if parts := strings.SplitN(path, `\`, 7); len(parts) >= 6 { - volumeName = strings.Join(parts[:6], `\`) - } else { - volumeName = filepath.VolumeName(path) - } - } else { - if !strings.HasPrefix(path, volumeGUIDPrefix) { // Handle volume GUID path - if strings.HasPrefix(path, uncPathPrefix) { - // Convert \\?\UNC\ extended path to standard path to get the volume name correctly - path = `\\` + path[len(uncPathPrefix):] - } else if strings.HasPrefix(path, extendedPathPrefix) { - //Extended length path prefix needs to be trimmed to get the volume name correctly - path = path[len(extendedPathPrefix):] - } else { - // Use the absolute path - path, err = filepath.Abs(path) - if err != nil { - return "", fmt.Errorf("failed to get absolute path: %w", err) - } + if !strings.HasSuffix(filepath.Clean(path), `\`) { + // Do not process file attributes and created time for windows directories like + // C:, D: + // Filepath.Clean(path) ends with '\' for Windows root drives only. + var sd *[]byte + if node.Type == "file" || node.Type == "dir" { + if sd, err = fs.GetSecurityDescriptor(path); err != nil { + return true, err } } - volumeName = filepath.VolumeName(path) + + // Add Windows attributes + node.GenericAttributes, err = WindowsAttrsToGenericAttributes(WindowsAttributes{ + CreationTime: getCreationTime(fi, path), + FileAttributes: &stat.FileAttributes, + SecurityDescriptor: sd, + }) } - return volumeName, nil + return true, err } // windowsAttrsToGenericAttributes converts the WindowsAttributes to a generic attributes map using reflection diff --git a/mover-restic/restic/internal/restic/node_windows_test.go b/mover-restic/restic/internal/restic/node_windows_test.go index 6ba25559b..4fd57bbb7 100644 --- a/mover-restic/restic/internal/restic/node_windows_test.go +++ b/mover-restic/restic/internal/restic/node_windows_test.go @@ -12,7 +12,6 @@ import ( "strings" "syscall" "testing" - "time" "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/fs" @@ -330,198 +329,3 @@ func TestRestoreExtendedAttributes(t *testing.T) { } } } - -func TestPrepareVolumeName(t *testing.T) { - currentVolume := filepath.VolumeName(func() string { - // Get the current working directory - pwd, err := os.Getwd() - if err != nil { - t.Fatalf("Failed to get current working directory: %v", err) - } - return pwd - }()) - // Create a temporary directory for the test - tempDir, err := os.MkdirTemp("", "restic_test_"+time.Now().Format("20060102150405")) - if err != nil { - t.Fatalf("Failed to create temp directory: %v", err) - } - defer os.RemoveAll(tempDir) - - // Create a long file name - longFileName := `\Very\Long\Path\That\Exceeds\260\Characters\` + strings.Repeat(`\VeryLongFolderName`, 20) + `\\LongFile.txt` - longFilePath := filepath.Join(tempDir, longFileName) - - tempDirVolume := filepath.VolumeName(tempDir) - // Create the file - content := []byte("This is a test file with a very long name.") - err = os.MkdirAll(filepath.Dir(longFilePath), 0755) - test.OK(t, err) - if err != nil { - t.Fatalf("Failed to create long folder: %v", err) - } - err = os.WriteFile(longFilePath, content, 0644) - test.OK(t, err) - if err != nil { - t.Fatalf("Failed to create long file: %v", err) - } - osVolumeGUIDPath := getOSVolumeGUIDPath(t) - osVolumeGUIDVolume := filepath.VolumeName(osVolumeGUIDPath) - - testCases := []struct { - name string - path string - expectedVolume string - expectError bool - expectedEASupported bool - isRealPath bool - }{ - { - name: "Network drive path", - path: `Z:\Shared\Documents`, - expectedVolume: `Z:`, - expectError: false, - expectedEASupported: false, - }, - { - name: "Subst drive path", - path: `X:\Virtual\Folder`, - expectedVolume: `X:`, - expectError: false, - expectedEASupported: false, - }, - { - name: "Windows reserved path", - path: `\\.\` + os.Getenv("SystemDrive") + `\System32\drivers\etc\hosts`, - expectedVolume: `\\.\` + os.Getenv("SystemDrive"), - expectError: false, - expectedEASupported: true, - isRealPath: true, - }, - { - name: "Long UNC path", - path: `\\?\UNC\LongServerName\VeryLongShareName\DeepPath\File.txt`, - expectedVolume: `\\LongServerName\VeryLongShareName`, - expectError: false, - expectedEASupported: false, - }, - { - name: "Volume GUID path", - path: osVolumeGUIDPath, - expectedVolume: osVolumeGUIDVolume, - expectError: false, - expectedEASupported: true, - isRealPath: true, - }, - { - name: "Volume GUID path with subfolder", - path: osVolumeGUIDPath + `\Windows`, - expectedVolume: osVolumeGUIDVolume, - expectError: false, - expectedEASupported: true, - isRealPath: true, - }, - { - name: "Standard path", - path: os.Getenv("SystemDrive") + `\Users\`, - expectedVolume: os.Getenv("SystemDrive"), - expectError: false, - expectedEASupported: true, - isRealPath: true, - }, - { - name: "Extended length path", - path: longFilePath, - expectedVolume: tempDirVolume, - expectError: false, - expectedEASupported: true, - isRealPath: true, - }, - { - name: "UNC path", - path: `\\server\share\folder`, - expectedVolume: `\\server\share`, - expectError: false, - expectedEASupported: false, - }, - { - name: "Extended UNC path", - path: `\\?\UNC\server\share\folder`, - expectedVolume: `\\server\share`, - expectError: false, - expectedEASupported: false, - }, - { - name: "Volume Shadow Copy path", - path: `\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Users\test`, - expectedVolume: `\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1`, - expectError: false, - expectedEASupported: false, - }, - { - name: "Relative path", - path: `folder\subfolder`, - - expectedVolume: currentVolume, // Get current volume - expectError: false, - expectedEASupported: true, - }, - { - name: "Empty path", - path: ``, - expectedVolume: currentVolume, - expectError: false, - expectedEASupported: true, - isRealPath: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - isEASupported, err := checkAndStoreEASupport(tc.path) - test.OK(t, err) - test.Equals(t, tc.expectedEASupported, isEASupported) - - volume, err := prepareVolumeName(tc.path) - - if tc.expectError { - test.Assert(t, err != nil, "Expected an error, but got none") - } else { - test.OK(t, err) - } - test.Equals(t, tc.expectedVolume, volume) - - if tc.isRealPath { - isEASupportedVolume, err := fs.PathSupportsExtendedAttributes(volume + `\`) - // If the prepared volume name is not valid, we will next fetch the actual volume name. - test.OK(t, err) - - test.Equals(t, tc.expectedEASupported, isEASupportedVolume) - - actualVolume, err := fs.GetVolumePathName(tc.path) - test.OK(t, err) - test.Equals(t, tc.expectedVolume, actualVolume) - } - }) - } -} - -func getOSVolumeGUIDPath(t *testing.T) string { - // Get the path of the OS drive (usually C:\) - osDrive := os.Getenv("SystemDrive") + "\\" - - // Convert to a volume GUID path - volumeName, err := windows.UTF16PtrFromString(osDrive) - test.OK(t, err) - if err != nil { - return "" - } - - var volumeGUID [windows.MAX_PATH]uint16 - err = windows.GetVolumeNameForVolumeMountPoint(volumeName, &volumeGUID[0], windows.MAX_PATH) - test.OK(t, err) - if err != nil { - return "" - } - - return windows.UTF16ToString(volumeGUID[:]) -} diff --git a/mover-restic/restic/internal/restic/snapshot_find.go b/mover-restic/restic/internal/restic/snapshot_find.go index 6eb51b237..6d1ab9a7a 100644 --- a/mover-restic/restic/internal/restic/snapshot_find.go +++ b/mover-restic/restic/internal/restic/snapshot_find.go @@ -134,10 +134,6 @@ func (f *SnapshotFilter) FindAll(ctx context.Context, be Lister, loader LoaderUn ids := NewIDSet() // Process all snapshot IDs given as arguments. for _, s := range snapshotIDs { - if ctx.Err() != nil { - return ctx.Err() - } - var sn *Snapshot if s == "latest" { if usedFilter { diff --git a/mover-restic/restic/internal/restorer/filerestorer.go b/mover-restic/restic/internal/restorer/filerestorer.go index 31234b960..e517e6284 100644 --- a/mover-restic/restic/internal/restorer/filerestorer.go +++ b/mover-restic/restic/internal/restorer/filerestorer.go @@ -122,10 +122,6 @@ func (r *fileRestorer) restoreFiles(ctx context.Context) error { // create packInfo from fileInfo for _, file := range r.files { - if ctx.Err() != nil { - return ctx.Err() - } - fileBlobs := file.blobs.(restic.IDs) largeFile := len(fileBlobs) > largeFileBlobCount var packsMap map[restic.ID][]fileBlobInfo diff --git a/mover-restic/restic/internal/restorer/fileswriter_test.go b/mover-restic/restic/internal/restorer/fileswriter_test.go index 9ea8767b8..c69847927 100644 --- a/mover-restic/restic/internal/restorer/fileswriter_test.go +++ b/mover-restic/restic/internal/restorer/fileswriter_test.go @@ -49,7 +49,7 @@ func TestFilesWriterRecursiveOverwrite(t *testing.T) { // must error if recursive delete is not allowed w := newFilesWriter(1, false) err := w.writeToFile(path, []byte{1}, 0, 2, false) - rtest.Assert(t, errors.Is(err, notEmptyDirError()), "unexpected error got %v", err) + rtest.Assert(t, errors.Is(err, notEmptyDirError()), "unexepected error got %v", err) rtest.Equals(t, 0, len(w.buckets[0].files)) // must replace directory diff --git a/mover-restic/restic/internal/restorer/restorer.go b/mover-restic/restic/internal/restorer/restorer.go index 0e30b82f8..cd3fd076d 100644 --- a/mover-restic/restic/internal/restorer/restorer.go +++ b/mover-restic/restic/internal/restorer/restorer.go @@ -12,7 +12,6 @@ import ( "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/fs" "github.com/restic/restic/internal/restic" - "github.com/restic/restic/internal/ui/progress" restoreui "github.com/restic/restic/internal/ui/restore" "golang.org/x/sync/errgroup" @@ -334,13 +333,12 @@ func (res *Restorer) ensureDir(target string) error { // RestoreTo creates the directories and files in the snapshot below dst. // Before an item is created, res.Filter is called. -func (res *Restorer) RestoreTo(ctx context.Context, dst string) (uint64, error) { - restoredFileCount := uint64(0) +func (res *Restorer) RestoreTo(ctx context.Context, dst string) error { var err error if !filepath.IsAbs(dst) { dst, err = filepath.Abs(dst) if err != nil { - return restoredFileCount, errors.Wrap(err, "Abs") + return errors.Wrap(err, "Abs") } } @@ -348,7 +346,7 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) (uint64, error) // ensure that the target directory exists and is actually a directory // Using ensureDir is too aggressive here as it also removes unexpected files if err := fs.MkdirAll(dst, 0700); err != nil { - return restoredFileCount, fmt.Errorf("cannot create target directory: %w", err) + return fmt.Errorf("cannot create target directory: %w", err) } } @@ -408,22 +406,19 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) (uint64, error) } } res.trackFile(location, updateMetadataOnly) - if !updateMetadataOnly { - restoredFileCount++ - } return nil }) return err }, }) if err != nil { - return 0, err + return err } if !res.opts.DryRun { err = filerestorer.restoreFiles(ctx) if err != nil { - return 0, err + return err } } @@ -455,7 +450,7 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) (uint64, error) }, leaveDir: func(node *restic.Node, target, location string, expectedFilenames []string) error { if res.opts.Delete { - if err := res.removeUnexpectedFiles(ctx, target, location, expectedFilenames); err != nil { + if err := res.removeUnexpectedFiles(target, location, expectedFilenames); err != nil { return err } } @@ -471,10 +466,10 @@ func (res *Restorer) RestoreTo(ctx context.Context, dst string) (uint64, error) return err }, }) - return restoredFileCount, err + return err } -func (res *Restorer) removeUnexpectedFiles(ctx context.Context, target, location string, expectedFilenames []string) error { +func (res *Restorer) removeUnexpectedFiles(target, location string, expectedFilenames []string) error { if !res.opts.Delete { panic("internal error") } @@ -492,10 +487,6 @@ func (res *Restorer) removeUnexpectedFiles(ctx context.Context, target, location } for _, entry := range entries { - if ctx.Err() != nil { - return ctx.Err() - } - if _, ok := keep[toComparableFilename(entry)]; ok { continue } @@ -592,7 +583,7 @@ const nVerifyWorkers = 8 // have been successfully written to dst. It stops when it encounters an // error. It returns that error and the number of files it has successfully // verified. -func (res *Restorer) VerifyFiles(ctx context.Context, dst string, countRestoredFiles uint64, p *progress.Counter) (int, error) { +func (res *Restorer) VerifyFiles(ctx context.Context, dst string) (int, error) { type mustCheck struct { node *restic.Node path string @@ -603,11 +594,6 @@ func (res *Restorer) VerifyFiles(ctx context.Context, dst string, countRestoredF work = make(chan mustCheck, 2*nVerifyWorkers) ) - if p != nil { - p.SetMax(countRestoredFiles) - defer p.Done() - } - g, ctx := errgroup.WithContext(ctx) // Traverse tree and send jobs to work. @@ -642,7 +628,6 @@ func (res *Restorer) VerifyFiles(ctx context.Context, dst string, countRestoredF if err != nil || ctx.Err() != nil { break } - p.Add(1) atomic.AddUint64(&nchecked, 1) } return err diff --git a/mover-restic/restic/internal/restorer/restorer_test.go b/mover-restic/restic/internal/restorer/restorer_test.go index 7d4895068..9c02afe68 100644 --- a/mover-restic/restic/internal/restorer/restorer_test.go +++ b/mover-restic/restic/internal/restorer/restorer_test.go @@ -22,7 +22,6 @@ import ( "github.com/restic/restic/internal/repository" "github.com/restic/restic/internal/restic" rtest "github.com/restic/restic/internal/test" - "github.com/restic/restic/internal/ui/progress" restoreui "github.com/restic/restic/internal/ui/restore" "golang.org/x/sync/errgroup" ) @@ -404,13 +403,13 @@ func TestRestorer(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - countRestoredFiles, err := res.RestoreTo(ctx, tempdir) + err := res.RestoreTo(ctx, tempdir) if err != nil { t.Fatal(err) } if len(test.ErrorsMust)+len(test.ErrorsMay) == 0 { - _, err = res.VerifyFiles(ctx, tempdir, countRestoredFiles, nil) + _, err = res.VerifyFiles(ctx, tempdir) rtest.OK(t, err) } @@ -502,18 +501,13 @@ func TestRestorerRelative(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - countRestoredFiles, err := res.RestoreTo(ctx, "restore") + err := res.RestoreTo(ctx, "restore") if err != nil { t.Fatal(err) } - p := progress.NewCounter(time.Second, countRestoredFiles, func(value uint64, total uint64, runtime time.Duration, final bool) {}) - defer p.Done() - nverified, err := res.VerifyFiles(ctx, "restore", countRestoredFiles, p) + nverified, err := res.VerifyFiles(ctx, "restore") rtest.OK(t, err) rtest.Equals(t, len(test.Files), nverified) - counterValue, maxValue := p.Get() - rtest.Equals(t, counterValue, uint64(2)) - rtest.Equals(t, maxValue, uint64(2)) for filename, err := range errors { t.Errorf("unexpected error for %v found: %v", filename, err) @@ -530,13 +524,6 @@ func TestRestorerRelative(t *testing.T) { t.Errorf("file %v has wrong content: want %q, got %q", filename, content, data) } } - - // verify that restoring the same snapshot again results in countRestoredFiles == 0 - countRestoredFiles, err = res.RestoreTo(ctx, "restore") - if err != nil { - t.Fatal(err) - } - rtest.Equals(t, uint64(0), countRestoredFiles) }) } } @@ -848,7 +835,7 @@ func TestRestorerConsistentTimestampsAndPermissions(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, err := res.RestoreTo(ctx, tempdir) + err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) var testPatterns = []struct { @@ -885,9 +872,9 @@ func TestVerifyCancel(t *testing.T) { tempdir := rtest.TempDir(t) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - countRestoredFiles, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) - err = os.WriteFile(filepath.Join(tempdir, "foo"), []byte("bar"), 0644) + + rtest.OK(t, res.RestoreTo(ctx, tempdir)) + err := os.WriteFile(filepath.Join(tempdir, "foo"), []byte("bar"), 0644) rtest.OK(t, err) var errs []error @@ -896,7 +883,7 @@ func TestVerifyCancel(t *testing.T) { return err } - nverified, err := res.VerifyFiles(ctx, tempdir, countRestoredFiles, nil) + nverified, err := res.VerifyFiles(ctx, tempdir) rtest.Equals(t, 0, nverified) rtest.Assert(t, err != nil, "nil error from VerifyFiles") rtest.Equals(t, 1, len(errs)) @@ -928,7 +915,7 @@ func TestRestorerSparseFiles(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, err = res.RestoreTo(ctx, tempdir) + err = res.RestoreTo(ctx, tempdir) rtest.OK(t, err) filename := filepath.Join(tempdir, "zeros") @@ -965,17 +952,15 @@ func saveSnapshotsAndOverwrite(t *testing.T, baseSnapshot Snapshot, overwriteSna t.Logf("base snapshot saved as %v", id.Str()) res := NewRestorer(repo, sn, baseOptions) - _, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) // overwrite snapshot sn, id = saveSnapshot(t, repo, overwriteSnapshot, noopGetGenericAttributes) t.Logf("overwrite snapshot saved as %v", id.Str()) res = NewRestorer(repo, sn, overwriteOptions) - countRestoredFiles, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) - _, err = res.VerifyFiles(ctx, tempdir, countRestoredFiles, nil) + _, err := res.VerifyFiles(ctx, tempdir) rtest.OK(t, err) return tempdir @@ -1004,9 +989,6 @@ type printerMock struct { func (p *printerMock) Update(_ restoreui.State, _ time.Duration) { } -func (p *printerMock) Error(item string, err error) error { - return nil -} func (p *printerMock) CompleteItem(action restoreui.ItemAction, item string, size uint64) { } func (p *printerMock) Finish(s restoreui.State, _ time.Duration) { @@ -1256,9 +1238,8 @@ func TestRestoreModified(t *testing.T) { t.Logf("snapshot saved as %v", id.Str()) res := NewRestorer(repo, sn, Options{Overwrite: OverwriteIfChanged}) - countRestoredFiles, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) - n, err := res.VerifyFiles(ctx, tempdir, countRestoredFiles, nil) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) + n, err := res.VerifyFiles(ctx, tempdir) rtest.OK(t, err) rtest.Equals(t, 2, n, "unexpected number of verified files") } @@ -1283,8 +1264,7 @@ func TestRestoreIfChanged(t *testing.T) { t.Logf("snapshot saved as %v", id.Str()) res := NewRestorer(repo, sn, Options{}) - _, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) // modify file but maintain size and timestamp path := filepath.Join(tempdir, "foo") @@ -1303,8 +1283,7 @@ func TestRestoreIfChanged(t *testing.T) { for _, overwrite := range []OverwriteBehavior{OverwriteIfChanged, OverwriteAlways} { res = NewRestorer(repo, sn, Options{Overwrite: overwrite}) - _, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) data, err := os.ReadFile(path) rtest.OK(t, err) if overwrite == OverwriteAlways { @@ -1340,10 +1319,9 @@ func TestRestoreDryRun(t *testing.T) { t.Logf("snapshot saved as %v", id.Str()) res := NewRestorer(repo, sn, Options{DryRun: true}) - _, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) - _, err = os.Stat(tempdir) + _, err := os.Stat(tempdir) rtest.Assert(t, errors.Is(err, os.ErrNotExist), "expected no file to be created, got %v", err) } @@ -1367,8 +1345,7 @@ func TestRestoreDryRunDelete(t *testing.T) { sn, _ := saveSnapshot(t, repo, snapshot, noopGetGenericAttributes) res := NewRestorer(repo, sn, Options{DryRun: true, Delete: true}) - _, err = res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) _, err = os.Stat(tempfile) rtest.Assert(t, err == nil, "expected file to still exist, got error %v", err) @@ -1486,14 +1463,14 @@ func TestRestoreDelete(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, err := res.RestoreTo(ctx, tempdir) + err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) res = NewRestorer(repo, deleteSn, Options{Delete: true}) if test.selectFilter != nil { res.SelectFilter = test.selectFilter } - _, err = res.RestoreTo(ctx, tempdir) + err = res.RestoreTo(ctx, tempdir) rtest.OK(t, err) for fn, shouldExist := range test.fileState { @@ -1526,40 +1503,6 @@ func TestRestoreToFile(t *testing.T) { sn, _ := saveSnapshot(t, repo, snapshot, noopGetGenericAttributes) res := NewRestorer(repo, sn, Options{}) - _, err := res.RestoreTo(ctx, tempdir) + err := res.RestoreTo(ctx, tempdir) rtest.Assert(t, strings.Contains(err.Error(), "cannot create target directory"), "unexpected error %v", err) } - -func TestRestorerLongPath(t *testing.T) { - tmp := t.TempDir() - - longPath := tmp - for i := 0; i < 20; i++ { - longPath = filepath.Join(longPath, "aaaaaaaaaaaaaaaaaaaa") - } - - rtest.OK(t, os.MkdirAll(longPath, 0o700)) - f, err := fs.OpenFile(filepath.Join(longPath, "file"), fs.O_CREATE|fs.O_RDWR, 0o600) - rtest.OK(t, err) - _, err = f.WriteString("Hello, World!") - rtest.OK(t, err) - rtest.OK(t, f.Close()) - - repo := repository.TestRepository(t) - - local := &fs.Local{} - sc := archiver.NewScanner(local) - rtest.OK(t, sc.Scan(context.TODO(), []string{tmp})) - arch := archiver.New(repo, local, archiver.Options{}) - sn, _, _, err := arch.Snapshot(context.Background(), []string{tmp}, archiver.SnapshotOptions{}) - rtest.OK(t, err) - - res := NewRestorer(repo, sn, Options{}) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - countRestoredFiles, err := res.RestoreTo(ctx, tmp) - rtest.OK(t, err) - _, err = res.VerifyFiles(ctx, tmp, countRestoredFiles, nil) - rtest.OK(t, err) -} diff --git a/mover-restic/restic/internal/restorer/restorer_unix_test.go b/mover-restic/restic/internal/restorer/restorer_unix_test.go index c4e8149b2..27d990af4 100644 --- a/mover-restic/restic/internal/restorer/restorer_unix_test.go +++ b/mover-restic/restic/internal/restorer/restorer_unix_test.go @@ -37,7 +37,7 @@ func TestRestorerRestoreEmptyHardlinkedFields(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, err := res.RestoreTo(ctx, tempdir) + err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) f1, err := os.Stat(filepath.Join(tempdir, "dirtest/file1")) @@ -96,7 +96,7 @@ func testRestorerProgressBar(t *testing.T, dryRun bool) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, err := res.RestoreTo(ctx, tempdir) + err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) progress.Finish() @@ -126,8 +126,7 @@ func TestRestorePermissions(t *testing.T) { t.Logf("snapshot saved as %v", id.Str()) res := NewRestorer(repo, sn, Options{}) - _, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) for _, overwrite := range []OverwriteBehavior{OverwriteIfChanged, OverwriteAlways} { // tamper with permissions @@ -135,8 +134,7 @@ func TestRestorePermissions(t *testing.T) { rtest.OK(t, os.Chmod(path, 0o700)) res = NewRestorer(repo, sn, Options{Overwrite: overwrite}) - _, err := res.RestoreTo(ctx, tempdir) - rtest.OK(t, err) + rtest.OK(t, res.RestoreTo(ctx, tempdir)) fi, err := os.Stat(path) rtest.OK(t, err) rtest.Equals(t, fs.FileMode(0o600), fi.Mode().Perm(), "unexpected permissions") diff --git a/mover-restic/restic/internal/restorer/restorer_windows.go b/mover-restic/restic/internal/restorer/restorer_windows.go index 9ddc0a932..72337d8ae 100644 --- a/mover-restic/restic/internal/restorer/restorer_windows.go +++ b/mover-restic/restic/internal/restorer/restorer_windows.go @@ -8,6 +8,6 @@ import "strings" // toComparableFilename returns a filename suitable for equality checks. On Windows, it returns the // uppercase version of the string. On all other systems, it returns the unmodified filename. func toComparableFilename(path string) string { - // apparently NTFS internally uppercases filenames for comparison + // apparently NTFS internally uppercases filenames for comparision return strings.ToUpper(path) } diff --git a/mover-restic/restic/internal/restorer/restorer_windows_test.go b/mover-restic/restic/internal/restorer/restorer_windows_test.go index 4764bed2d..3f6c8472b 100644 --- a/mover-restic/restic/internal/restorer/restorer_windows_test.go +++ b/mover-restic/restic/internal/restorer/restorer_windows_test.go @@ -181,7 +181,7 @@ func runAttributeTests(t *testing.T, fileInfo NodeInfo, existingFileAttr FileAtt ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, err := res.RestoreTo(ctx, testDir) + err := res.RestoreTo(ctx, testDir) rtest.OK(t, err) mainFilePath := path.Join(testDir, fileInfo.parentDir, fileInfo.name) @@ -562,11 +562,11 @@ func TestRestoreDeleteCaseInsensitive(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, err := res.RestoreTo(ctx, tempdir) + err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) res = NewRestorer(repo, deleteSn, Options{Delete: true}) - _, err = res.RestoreTo(ctx, tempdir) + err = res.RestoreTo(ctx, tempdir) rtest.OK(t, err) // anotherfile must still exist diff --git a/mover-restic/restic/internal/ui/backup/json.go b/mover-restic/restic/internal/ui/backup/json.go index f4a76afd7..64b5de13b 100644 --- a/mover-restic/restic/internal/ui/backup/json.go +++ b/mover-restic/restic/internal/ui/backup/json.go @@ -7,13 +7,14 @@ import ( "github.com/restic/restic/internal/archiver" "github.com/restic/restic/internal/restic" "github.com/restic/restic/internal/ui" + "github.com/restic/restic/internal/ui/termstatus" ) // JSONProgress reports progress for the `backup` command in JSON. type JSONProgress struct { *ui.Message - term ui.Terminal + term *termstatus.Terminal v uint } @@ -21,7 +22,7 @@ type JSONProgress struct { var _ ProgressPrinter = &JSONProgress{} // NewJSONProgress returns a new backup progress reporter. -func NewJSONProgress(term ui.Terminal, verbosity uint) *JSONProgress { +func NewJSONProgress(term *termstatus.Terminal, verbosity uint) *JSONProgress { return &JSONProgress{ Message: ui.NewMessage(term, verbosity), term: term, @@ -67,7 +68,7 @@ func (b *JSONProgress) Update(total, processed Counter, errors uint, currentFile func (b *JSONProgress) ScannerError(item string, err error) error { b.error(errorUpdate{ MessageType: "error", - Error: errorObject{err.Error()}, + Error: err, During: "scan", Item: item, }) @@ -78,7 +79,7 @@ func (b *JSONProgress) ScannerError(item string, err error) error { func (b *JSONProgress) Error(item string, err error) error { b.error(errorUpdate{ MessageType: "error", - Error: errorObject{err.Error()}, + Error: err, During: "archival", Item: item, }) @@ -205,15 +206,11 @@ type statusUpdate struct { CurrentFiles []string `json:"current_files,omitempty"` } -type errorObject struct { - Message string `json:"message"` -} - type errorUpdate struct { - MessageType string `json:"message_type"` // "error" - Error errorObject `json:"error"` - During string `json:"during"` - Item string `json:"item"` + MessageType string `json:"message_type"` // "error" + Error error `json:"error"` + During string `json:"during"` + Item string `json:"item"` } type verboseUpdate struct { diff --git a/mover-restic/restic/internal/ui/backup/json_test.go b/mover-restic/restic/internal/ui/backup/json_test.go deleted file mode 100644 index b4872efd5..000000000 --- a/mover-restic/restic/internal/ui/backup/json_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package backup - -import ( - "testing" - - "github.com/restic/restic/internal/errors" - "github.com/restic/restic/internal/test" - "github.com/restic/restic/internal/ui" -) - -func createJSONProgress() (*ui.MockTerminal, ProgressPrinter) { - term := &ui.MockTerminal{} - printer := NewJSONProgress(term, 3) - return term, printer -} - -func TestJSONError(t *testing.T) { - term, printer := createJSONProgress() - test.Equals(t, printer.Error("/path", errors.New("error \"message\"")), nil) - test.Equals(t, []string{"{\"message_type\":\"error\",\"error\":{\"message\":\"error \\\"message\\\"\"},\"during\":\"archival\",\"item\":\"/path\"}\n"}, term.Errors) -} - -func TestJSONScannerError(t *testing.T) { - term, printer := createJSONProgress() - test.Equals(t, printer.ScannerError("/path", errors.New("error \"message\"")), nil) - test.Equals(t, []string{"{\"message_type\":\"error\",\"error\":{\"message\":\"error \\\"message\\\"\"},\"during\":\"scan\",\"item\":\"/path\"}\n"}, term.Errors) -} diff --git a/mover-restic/restic/internal/ui/backup/text.go b/mover-restic/restic/internal/ui/backup/text.go index 097f0d0d8..f96746739 100644 --- a/mover-restic/restic/internal/ui/backup/text.go +++ b/mover-restic/restic/internal/ui/backup/text.go @@ -15,19 +15,17 @@ import ( type TextProgress struct { *ui.Message - term ui.Terminal - verbosity uint + term *termstatus.Terminal } // assert that Backup implements the ProgressPrinter interface var _ ProgressPrinter = &TextProgress{} // NewTextProgress returns a new backup progress reporter. -func NewTextProgress(term ui.Terminal, verbosity uint) *TextProgress { +func NewTextProgress(term *termstatus.Terminal, verbosity uint) *TextProgress { return &TextProgress{ - Message: ui.NewMessage(term, verbosity), - term: term, - verbosity: verbosity, + Message: ui.NewMessage(term, verbosity), + term: term, } } @@ -75,9 +73,7 @@ func (b *TextProgress) Update(total, processed Counter, errors uint, currentFile // ScannerError is the error callback function for the scanner, it prints the // error in verbose mode and returns nil. func (b *TextProgress) ScannerError(_ string, err error) error { - if b.verbosity >= 2 { - b.E("scan: %v\n", err) - } + b.V("scan: %v\n", err) return nil } diff --git a/mover-restic/restic/internal/ui/backup/text_test.go b/mover-restic/restic/internal/ui/backup/text_test.go deleted file mode 100644 index 39338a50c..000000000 --- a/mover-restic/restic/internal/ui/backup/text_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package backup - -import ( - "testing" - - "github.com/restic/restic/internal/errors" - "github.com/restic/restic/internal/test" - "github.com/restic/restic/internal/ui" -) - -func createTextProgress() (*ui.MockTerminal, ProgressPrinter) { - term := &ui.MockTerminal{} - printer := NewTextProgress(term, 3) - return term, printer -} - -func TestError(t *testing.T) { - term, printer := createTextProgress() - test.Equals(t, printer.Error("/path", errors.New("error \"message\"")), nil) - test.Equals(t, []string{"error: error \"message\"\n"}, term.Errors) -} - -func TestScannerError(t *testing.T) { - term, printer := createTextProgress() - test.Equals(t, printer.ScannerError("/path", errors.New("error \"message\"")), nil) - test.Equals(t, []string{"scan: error \"message\"\n"}, term.Errors) -} diff --git a/mover-restic/restic/internal/ui/message.go b/mover-restic/restic/internal/ui/message.go index 6ad5a439e..38cdaf301 100644 --- a/mover-restic/restic/internal/ui/message.go +++ b/mover-restic/restic/internal/ui/message.go @@ -2,17 +2,19 @@ package ui import ( "fmt" + + "github.com/restic/restic/internal/ui/termstatus" ) // Message reports progress with messages of different verbosity. type Message struct { - term Terminal + term *termstatus.Terminal v uint } // NewMessage returns a message progress reporter with underlying terminal // term. -func NewMessage(term Terminal, verbosity uint) *Message { +func NewMessage(term *termstatus.Terminal, verbosity uint) *Message { return &Message{ term: term, v: verbosity, diff --git a/mover-restic/restic/internal/ui/mock.go b/mover-restic/restic/internal/ui/mock.go deleted file mode 100644 index 5a4debb02..000000000 --- a/mover-restic/restic/internal/ui/mock.go +++ /dev/null @@ -1,22 +0,0 @@ -package ui - -type MockTerminal struct { - Output []string - Errors []string -} - -func (m *MockTerminal) Print(line string) { - m.Output = append(m.Output, line) -} - -func (m *MockTerminal) Error(line string) { - m.Errors = append(m.Errors, line) -} - -func (m *MockTerminal) SetStatus(lines []string) { - m.Output = append([]string{}, lines...) -} - -func (m *MockTerminal) CanUpdateStatus() bool { - return true -} diff --git a/mover-restic/restic/internal/ui/restore/json.go b/mover-restic/restic/internal/ui/restore/json.go index 72cc38a6e..c248a7951 100644 --- a/mover-restic/restic/internal/ui/restore/json.go +++ b/mover-restic/restic/internal/ui/restore/json.go @@ -7,11 +7,11 @@ import ( ) type jsonPrinter struct { - terminal ui.Terminal + terminal term verbosity uint } -func NewJSONProgress(terminal ui.Terminal, verbosity uint) ProgressPrinter { +func NewJSONProgress(terminal term, verbosity uint) ProgressPrinter { return &jsonPrinter{ terminal: terminal, verbosity: verbosity, @@ -22,10 +22,6 @@ func (t *jsonPrinter) print(status interface{}) { t.terminal.Print(ui.ToJSONString(status)) } -func (t *jsonPrinter) error(status interface{}) { - t.terminal.Error(ui.ToJSONString(status)) -} - func (t *jsonPrinter) Update(p State, duration time.Duration) { status := statusUpdate{ MessageType: "status", @@ -45,16 +41,6 @@ func (t *jsonPrinter) Update(p State, duration time.Duration) { t.print(status) } -func (t *jsonPrinter) Error(item string, err error) error { - t.error(errorUpdate{ - MessageType: "error", - Error: errorObject{err.Error()}, - During: "restore", - Item: item, - }) - return nil -} - func (t *jsonPrinter) CompleteItem(messageType ItemAction, item string, size uint64) { if t.verbosity < 3 { return @@ -113,17 +99,6 @@ type statusUpdate struct { BytesSkipped uint64 `json:"bytes_skipped,omitempty"` } -type errorObject struct { - Message string `json:"message"` -} - -type errorUpdate struct { - MessageType string `json:"message_type"` // "error" - Error errorObject `json:"error"` - During string `json:"during"` - Item string `json:"item"` -} - type verboseUpdate struct { MessageType string `json:"message_type"` // "verbose_status" Action string `json:"action"` diff --git a/mover-restic/restic/internal/ui/restore/json_test.go b/mover-restic/restic/internal/ui/restore/json_test.go index 917a48070..06a70d5dc 100644 --- a/mover-restic/restic/internal/ui/restore/json_test.go +++ b/mover-restic/restic/internal/ui/restore/json_test.go @@ -4,13 +4,11 @@ import ( "testing" "time" - "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/test" - "github.com/restic/restic/internal/ui" ) -func createJSONProgress() (*ui.MockTerminal, ProgressPrinter) { - term := &ui.MockTerminal{} +func createJSONProgress() (*mockTerm, ProgressPrinter) { + term := &mockTerm{} printer := NewJSONProgress(term, 3) return term, printer } @@ -18,31 +16,31 @@ func createJSONProgress() (*ui.MockTerminal, ProgressPrinter) { func TestJSONPrintUpdate(t *testing.T) { term, printer := createJSONProgress() printer.Update(State{3, 11, 0, 29, 47, 0}, 5*time.Second) - test.Equals(t, []string{"{\"message_type\":\"status\",\"seconds_elapsed\":5,\"percent_done\":0.6170212765957447,\"total_files\":11,\"files_restored\":3,\"total_bytes\":47,\"bytes_restored\":29}\n"}, term.Output) + test.Equals(t, []string{"{\"message_type\":\"status\",\"seconds_elapsed\":5,\"percent_done\":0.6170212765957447,\"total_files\":11,\"files_restored\":3,\"total_bytes\":47,\"bytes_restored\":29}\n"}, term.output) } func TestJSONPrintUpdateWithSkipped(t *testing.T) { term, printer := createJSONProgress() printer.Update(State{3, 11, 2, 29, 47, 59}, 5*time.Second) - test.Equals(t, []string{"{\"message_type\":\"status\",\"seconds_elapsed\":5,\"percent_done\":0.6170212765957447,\"total_files\":11,\"files_restored\":3,\"files_skipped\":2,\"total_bytes\":47,\"bytes_restored\":29,\"bytes_skipped\":59}\n"}, term.Output) + test.Equals(t, []string{"{\"message_type\":\"status\",\"seconds_elapsed\":5,\"percent_done\":0.6170212765957447,\"total_files\":11,\"files_restored\":3,\"files_skipped\":2,\"total_bytes\":47,\"bytes_restored\":29,\"bytes_skipped\":59}\n"}, term.output) } func TestJSONPrintSummaryOnSuccess(t *testing.T) { term, printer := createJSONProgress() printer.Finish(State{11, 11, 0, 47, 47, 0}, 5*time.Second) - test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":11,\"total_bytes\":47,\"bytes_restored\":47}\n"}, term.Output) + test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":11,\"total_bytes\":47,\"bytes_restored\":47}\n"}, term.output) } func TestJSONPrintSummaryOnErrors(t *testing.T) { term, printer := createJSONProgress() printer.Finish(State{3, 11, 0, 29, 47, 0}, 5*time.Second) - test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":3,\"total_bytes\":47,\"bytes_restored\":29}\n"}, term.Output) + test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":3,\"total_bytes\":47,\"bytes_restored\":29}\n"}, term.output) } func TestJSONPrintSummaryOnSuccessWithSkipped(t *testing.T) { term, printer := createJSONProgress() printer.Finish(State{11, 11, 2, 47, 47, 59}, 5*time.Second) - test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":11,\"files_skipped\":2,\"total_bytes\":47,\"bytes_restored\":47,\"bytes_skipped\":59}\n"}, term.Output) + test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":11,\"files_skipped\":2,\"total_bytes\":47,\"bytes_restored\":47,\"bytes_skipped\":59}\n"}, term.output) } func TestJSONPrintCompleteItem(t *testing.T) { @@ -59,12 +57,6 @@ func TestJSONPrintCompleteItem(t *testing.T) { } { term, printer := createJSONProgress() printer.CompleteItem(data.action, "test", data.size) - test.Equals(t, []string{data.expected}, term.Output) + test.Equals(t, []string{data.expected}, term.output) } } - -func TestJSONError(t *testing.T) { - term, printer := createJSONProgress() - test.Equals(t, printer.Error("/path", errors.New("error \"message\"")), nil) - test.Equals(t, []string{"{\"message_type\":\"error\",\"error\":{\"message\":\"error \\\"message\\\"\"},\"during\":\"restore\",\"item\":\"/path\"}\n"}, term.Errors) -} diff --git a/mover-restic/restic/internal/ui/restore/progress.go b/mover-restic/restic/internal/ui/restore/progress.go index 06f4c86aa..67b15f07e 100644 --- a/mover-restic/restic/internal/ui/restore/progress.go +++ b/mover-restic/restic/internal/ui/restore/progress.go @@ -32,9 +32,13 @@ type progressInfoEntry struct { bytesTotal uint64 } +type term interface { + Print(line string) + SetStatus(lines []string) +} + type ProgressPrinter interface { Update(progress State, duration time.Duration) - Error(item string, err error) error CompleteItem(action ItemAction, item string, size uint64) Finish(progress State, duration time.Duration) } @@ -135,17 +139,6 @@ func (p *Progress) ReportDeletedFile(name string) { p.printer.CompleteItem(ActionDeleted, name, 0) } -func (p *Progress) Error(item string, err error) error { - if p == nil { - return nil - } - - p.m.Lock() - defer p.m.Unlock() - - return p.printer.Error(item, err) -} - func (p *Progress) Finish() { p.updater.Done() } diff --git a/mover-restic/restic/internal/ui/restore/progress_test.go b/mover-restic/restic/internal/ui/restore/progress_test.go index b01440bee..4a6304741 100644 --- a/mover-restic/restic/internal/ui/restore/progress_test.go +++ b/mover-restic/restic/internal/ui/restore/progress_test.go @@ -4,7 +4,6 @@ import ( "testing" "time" - "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/test" ) @@ -24,18 +23,9 @@ type itemTraceEntry struct { } type itemTrace []itemTraceEntry - -type errorTraceEntry struct { - item string - err error -} - -type errorTrace []errorTraceEntry - type mockPrinter struct { - trace printerTrace - items itemTrace - errors errorTrace + trace printerTrace + items itemTrace } const mockFinishDuration = 42 * time.Second @@ -43,10 +33,6 @@ const mockFinishDuration = 42 * time.Second func (p *mockPrinter) Update(progress State, duration time.Duration) { p.trace = append(p.trace, printerTraceEntry{progress, duration, false}) } -func (p *mockPrinter) Error(item string, err error) error { - p.errors = append(p.errors, errorTraceEntry{item, err}) - return nil -} func (p *mockPrinter) CompleteItem(action ItemAction, item string, size uint64) { p.items = append(p.items, itemTraceEntry{action, item, size}) } @@ -54,21 +40,20 @@ func (p *mockPrinter) Finish(progress State, _ time.Duration) { p.trace = append(p.trace, printerTraceEntry{progress, mockFinishDuration, true}) } -func testProgress(fn func(progress *Progress) bool) (printerTrace, itemTrace, errorTrace) { +func testProgress(fn func(progress *Progress) bool) (printerTrace, itemTrace) { printer := &mockPrinter{} progress := NewProgress(printer, 0) final := fn(progress) progress.update(0, final) trace := append(printerTrace{}, printer.trace...) items := append(itemTrace{}, printer.items...) - errors := append(errorTrace{}, printer.errors...) // cleanup to avoid goroutine leak, but copy trace first progress.Finish() - return trace, items, errors + return trace, items } func TestNew(t *testing.T) { - result, items, _ := testProgress(func(progress *Progress) bool { + result, items := testProgress(func(progress *Progress) bool { return false }) test.Equals(t, printerTrace{ @@ -80,7 +65,7 @@ func TestNew(t *testing.T) { func TestAddFile(t *testing.T) { fileSize := uint64(100) - result, items, _ := testProgress(func(progress *Progress) bool { + result, items := testProgress(func(progress *Progress) bool { progress.AddFile(fileSize) return false }) @@ -94,7 +79,7 @@ func TestFirstProgressOnAFile(t *testing.T) { expectedBytesWritten := uint64(5) expectedBytesTotal := uint64(100) - result, items, _ := testProgress(func(progress *Progress) bool { + result, items := testProgress(func(progress *Progress) bool { progress.AddFile(expectedBytesTotal) progress.AddProgress("test", ActionFileUpdated, expectedBytesWritten, expectedBytesTotal) return false @@ -108,7 +93,7 @@ func TestFirstProgressOnAFile(t *testing.T) { func TestLastProgressOnAFile(t *testing.T) { fileSize := uint64(100) - result, items, _ := testProgress(func(progress *Progress) bool { + result, items := testProgress(func(progress *Progress) bool { progress.AddFile(fileSize) progress.AddProgress("test", ActionFileUpdated, 30, fileSize) progress.AddProgress("test", ActionFileUpdated, 35, fileSize) @@ -126,7 +111,7 @@ func TestLastProgressOnAFile(t *testing.T) { func TestLastProgressOnLastFile(t *testing.T) { fileSize := uint64(100) - result, items, _ := testProgress(func(progress *Progress) bool { + result, items := testProgress(func(progress *Progress) bool { progress.AddFile(fileSize) progress.AddFile(50) progress.AddProgress("test1", ActionFileUpdated, 50, 50) @@ -146,7 +131,7 @@ func TestLastProgressOnLastFile(t *testing.T) { func TestSummaryOnSuccess(t *testing.T) { fileSize := uint64(100) - result, _, _ := testProgress(func(progress *Progress) bool { + result, _ := testProgress(func(progress *Progress) bool { progress.AddFile(fileSize) progress.AddFile(50) progress.AddProgress("test1", ActionFileUpdated, 50, 50) @@ -161,7 +146,7 @@ func TestSummaryOnSuccess(t *testing.T) { func TestSummaryOnErrors(t *testing.T) { fileSize := uint64(100) - result, _, _ := testProgress(func(progress *Progress) bool { + result, _ := testProgress(func(progress *Progress) bool { progress.AddFile(fileSize) progress.AddFile(50) progress.AddProgress("test1", ActionFileUpdated, 50, 50) @@ -176,7 +161,7 @@ func TestSummaryOnErrors(t *testing.T) { func TestSkipFile(t *testing.T) { fileSize := uint64(100) - result, items, _ := testProgress(func(progress *Progress) bool { + result, items := testProgress(func(progress *Progress) bool { progress.AddSkippedFile("test", fileSize) return true }) @@ -191,7 +176,7 @@ func TestSkipFile(t *testing.T) { func TestProgressTypes(t *testing.T) { fileSize := uint64(100) - _, items, _ := testProgress(func(progress *Progress) bool { + _, items := testProgress(func(progress *Progress) bool { progress.AddFile(fileSize) progress.AddFile(0) progress.AddProgress("dir", ActionDirRestored, fileSize, fileSize) @@ -205,17 +190,3 @@ func TestProgressTypes(t *testing.T) { itemTraceEntry{ActionDeleted, "del", 0}, }, items) } - -func TestProgressError(t *testing.T) { - err1 := errors.New("err1") - err2 := errors.New("err2") - _, _, errors := testProgress(func(progress *Progress) bool { - test.Equals(t, progress.Error("first", err1), nil) - test.Equals(t, progress.Error("second", err2), nil) - return true - }) - test.Equals(t, errorTrace{ - errorTraceEntry{"first", err1}, - errorTraceEntry{"second", err2}, - }, errors) -} diff --git a/mover-restic/restic/internal/ui/restore/text.go b/mover-restic/restic/internal/ui/restore/text.go index ba0dcd007..ec512f369 100644 --- a/mover-restic/restic/internal/ui/restore/text.go +++ b/mover-restic/restic/internal/ui/restore/text.go @@ -8,15 +8,14 @@ import ( ) type textPrinter struct { - *ui.Message - - terminal ui.Terminal + terminal term + verbosity uint } -func NewTextProgress(terminal ui.Terminal, verbosity uint) ProgressPrinter { +func NewTextProgress(terminal term, verbosity uint) ProgressPrinter { return &textPrinter{ - Message: ui.NewMessage(terminal, verbosity), - terminal: terminal, + terminal: terminal, + verbosity: verbosity, } } @@ -34,12 +33,11 @@ func (t *textPrinter) Update(p State, duration time.Duration) { t.terminal.SetStatus([]string{progress}) } -func (t *textPrinter) Error(item string, err error) error { - t.E("ignoring error for %s: %s\n", item, err) - return nil -} - func (t *textPrinter) CompleteItem(messageType ItemAction, item string, size uint64) { + if t.verbosity < 3 { + return + } + var action string switch messageType { case ActionDirRestored: @@ -59,9 +57,9 @@ func (t *textPrinter) CompleteItem(messageType ItemAction, item string, size uin } if messageType == ActionDirRestored || messageType == ActionOtherRestored || messageType == ActionDeleted { - t.VV("%-9v %v", action, item) + t.terminal.Print(fmt.Sprintf("%-9v %v", action, item)) } else { - t.VV("%-9v %v with size %v", action, item, ui.FormatBytes(size)) + t.terminal.Print(fmt.Sprintf("%-9v %v with size %v", action, item, ui.FormatBytes(size))) } } diff --git a/mover-restic/restic/internal/ui/restore/text_test.go b/mover-restic/restic/internal/ui/restore/text_test.go index 4ffb1615d..b198a27df 100644 --- a/mover-restic/restic/internal/ui/restore/text_test.go +++ b/mover-restic/restic/internal/ui/restore/text_test.go @@ -4,13 +4,23 @@ import ( "testing" "time" - "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/test" - "github.com/restic/restic/internal/ui" ) -func createTextProgress() (*ui.MockTerminal, ProgressPrinter) { - term := &ui.MockTerminal{} +type mockTerm struct { + output []string +} + +func (m *mockTerm) Print(line string) { + m.output = append(m.output, line) +} + +func (m *mockTerm) SetStatus(lines []string) { + m.output = append([]string{}, lines...) +} + +func createTextProgress() (*mockTerm, ProgressPrinter) { + term := &mockTerm{} printer := NewTextProgress(term, 3) return term, printer } @@ -18,31 +28,31 @@ func createTextProgress() (*ui.MockTerminal, ProgressPrinter) { func TestPrintUpdate(t *testing.T) { term, printer := createTextProgress() printer.Update(State{3, 11, 0, 29, 47, 0}, 5*time.Second) - test.Equals(t, []string{"[0:05] 61.70% 3 files/dirs 29 B, total 11 files/dirs 47 B"}, term.Output) + test.Equals(t, []string{"[0:05] 61.70% 3 files/dirs 29 B, total 11 files/dirs 47 B"}, term.output) } func TestPrintUpdateWithSkipped(t *testing.T) { term, printer := createTextProgress() printer.Update(State{3, 11, 2, 29, 47, 59}, 5*time.Second) - test.Equals(t, []string{"[0:05] 61.70% 3 files/dirs 29 B, total 11 files/dirs 47 B, skipped 2 files/dirs 59 B"}, term.Output) + test.Equals(t, []string{"[0:05] 61.70% 3 files/dirs 29 B, total 11 files/dirs 47 B, skipped 2 files/dirs 59 B"}, term.output) } func TestPrintSummaryOnSuccess(t *testing.T) { term, printer := createTextProgress() printer.Finish(State{11, 11, 0, 47, 47, 0}, 5*time.Second) - test.Equals(t, []string{"Summary: Restored 11 files/dirs (47 B) in 0:05"}, term.Output) + test.Equals(t, []string{"Summary: Restored 11 files/dirs (47 B) in 0:05"}, term.output) } func TestPrintSummaryOnErrors(t *testing.T) { term, printer := createTextProgress() printer.Finish(State{3, 11, 0, 29, 47, 0}, 5*time.Second) - test.Equals(t, []string{"Summary: Restored 3 / 11 files/dirs (29 B / 47 B) in 0:05"}, term.Output) + test.Equals(t, []string{"Summary: Restored 3 / 11 files/dirs (29 B / 47 B) in 0:05"}, term.output) } func TestPrintSummaryOnSuccessWithSkipped(t *testing.T) { term, printer := createTextProgress() printer.Finish(State{11, 11, 2, 47, 47, 59}, 5*time.Second) - test.Equals(t, []string{"Summary: Restored 11 files/dirs (47 B) in 0:05, skipped 2 files/dirs 59 B"}, term.Output) + test.Equals(t, []string{"Summary: Restored 11 files/dirs (47 B) in 0:05, skipped 2 files/dirs 59 B"}, term.output) } func TestPrintCompleteItem(t *testing.T) { @@ -60,12 +70,6 @@ func TestPrintCompleteItem(t *testing.T) { } { term, printer := createTextProgress() printer.CompleteItem(data.action, "test", data.size) - test.Equals(t, []string{data.expected}, term.Output) + test.Equals(t, []string{data.expected}, term.output) } } - -func TestError(t *testing.T) { - term, printer := createTextProgress() - test.Equals(t, printer.Error("/path", errors.New("error \"message\"")), nil) - test.Equals(t, []string{"ignoring error for /path: error \"message\"\n"}, term.Errors) -} diff --git a/mover-restic/restic/internal/ui/terminal.go b/mover-restic/restic/internal/ui/terminal.go deleted file mode 100644 index 2d9418a61..000000000 --- a/mover-restic/restic/internal/ui/terminal.go +++ /dev/null @@ -1,10 +0,0 @@ -package ui - -// Terminal is used to write messages and display status lines which can be -// updated. See termstatus.Terminal for a concrete implementation. -type Terminal interface { - Print(line string) - Error(line string) - SetStatus(lines []string) - CanUpdateStatus() bool -} diff --git a/mover-restic/restic/internal/walker/rewriter.go b/mover-restic/restic/internal/walker/rewriter.go index 7e984ae25..6c27b26ac 100644 --- a/mover-restic/restic/internal/walker/rewriter.go +++ b/mover-restic/restic/internal/walker/rewriter.go @@ -116,10 +116,6 @@ func (t *TreeRewriter) RewriteTree(ctx context.Context, repo BlobLoadSaver, node tb := restic.NewTreeJSONBuilder() for _, node := range curTree.Nodes { - if ctx.Err() != nil { - return restic.ID{}, ctx.Err() - } - path := path.Join(nodepath, node.Name) node = t.opts.RewriteNode(node, path) if node == nil { diff --git a/mover-restic/restic/internal/walker/walker.go b/mover-restic/restic/internal/walker/walker.go index 788ece1cf..091b05489 100644 --- a/mover-restic/restic/internal/walker/walker.go +++ b/mover-restic/restic/internal/walker/walker.go @@ -57,10 +57,6 @@ func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTree }) for _, node := range tree.Nodes { - if ctx.Err() != nil { - return ctx.Err() - } - p := path.Join(prefix, node.Name) if node.Type == "" {