Compare commits

...

274 Commits

Author SHA1 Message Date
Alexander Neumann
cd9b2295f1 Add version for 0.9.4 2019-01-06 21:40:32 +01:00
Alexander Neumann
a439cdeb05 Update manpages and auto-completion 2019-01-06 21:40:32 +01:00
Alexander Neumann
827f6d7b24 Generate CHANGELOG.md for 0.9.4 2019-01-06 21:40:31 +01:00
Alexander Neumann
77ab10d401 Create changelog dir for 0.9.4 2019-01-06 21:39:56 +01:00
Alexander Neumann
3b0ad2e368 release: Pull latest alpine image 2019-01-06 21:39:56 +01:00
Alexander Neumann
2996c110f1 Merge pull request 2017 from kylewlacy/fuse_default_permissions_option
mount: Add default-permissions flag to set FUSE option
2019-01-06 21:19:27 +01:00
Alexander Neumann
4609b5c24d Merge pull request 2094 from juergenhoetzel/password-command
Add support for reading password from external command
2019-01-06 21:14:52 +01:00
Alexander Neumann
830511460a mount: Turn on DefaultPermissions for --allow-other`
This commit changes the logic slightly: checking the permissions in the
fuse mount when nobody else besides the current user can access the fuse
mount does not sense. The current user has access to the repo files in
addition to the password, so they can access all data regardless of what
the fuse mount does.

Enabling `--allow-root` allows the root user to access the files in the
fuse mount, for this user no permission checks will be done anyway.

The code now enables `DefaultPermissions` automatically when
`--allow-other` is set, it can be disabled with
`--no-default-permissions` to restore the old behavior.
2019-01-06 20:55:49 +01:00
Alexander Neumann
0dc3648416 Add documentation for --password-command 2019-01-06 20:41:38 +01:00
Alexander Neumann
d71dba3788 Merge pull request 2130 from andreaso/docs-https-links
Prefer https:// links in the documentation
2019-01-06 20:24:42 +01:00
Alexander Neumann
e482633943 Merge pull request 2137 from kevinawoo/patch-1
doc: Add more clarity to B2 application key
2019-01-06 20:24:00 +01:00
Alexander Neumann
900621051a Merge pull request 2120 from turnkey-commerce/fix-doc-typo
Fix a few typos in the FAQ doc.
2019-01-06 15:08:13 +01:00
Alexander Neumann
1f246c5309 Merge pull request 2090 from plumbeo/within-hours
Increase the granularity of the "keep within" snapshot retention policy
2019-01-06 15:04:55 +01:00
Alexander Neumann
e40805b002 Merge pull request 2103 from cdhowie/master
--one-file-system unsupported on Windows
2019-01-06 14:59:46 +01:00
Kevin Woo
d65bea1b2a doc: Add more clarity to B2 application key 2019-01-05 20:05:11 -08:00
Andreas Olsson
3b68acf853 Prefer https:// links in the documentation
All the changed urls are available by way of https://. Most of them
already redirect.
2018-12-29 15:57:44 +01:00
James Culbertson
82a70643a2 Fix a few typos in the FAQ doc. 2018-12-18 08:47:52 -06:00
Alexander Neumann
0dd805421e Merge pull request 2108 from mholt/noexitprint
cmd: Don't exit if printing to stdout or stderr fails (closes #2102)
2018-12-15 21:34:18 +01:00
Alexander Neumann
16b82f4b1d Merge pull request 2111 from andreaso/doc-moot-sudo
Remove moot sudo usage from documentation
2018-12-15 21:33:51 +01:00
Andreas Olsson
7a6bfcd58c Remove moot sudo usage from documentation
That usage of sudo only applies to the echo command itself. It has no
effect on the permissions of the stdout redirect.
2018-12-09 17:43:50 +01:00
Matthew Holt
de54618852 cmd: Don't exit if printing to stdout or stderr fails (closes #2102) 2018-12-01 15:11:22 -07:00
Alexander Neumann
98526b8dbe Merge pull request 2100 from restic/fix-1989
gs: Respect bandwidth limiting
2018-11-28 21:39:42 +01:00
Alexander Neumann
0083680d33 Merge pull request 2099 from restic/fix-1229
cache: Don't return an error for truncated files
2018-11-28 21:39:35 +01:00
Chris Howie
05222b7343 --one-file-system unsupported on Windows 2018-11-27 11:14:47 -05:00
Kyle Lacy
d4ff5b6bf4 Add changelog entry about "DefaultPermissions" change 2018-11-26 21:16:01 -08:00
Kyle Lacy
cf0883e16c mount: Add "no-default-permissions" option
This option restores the previous behavior of `mount` by disabling the "DefaultPermissions" FUSE option. This allows any user that can access the mountpoint to read any file from the snapshot. Normal FUSE rules apply, so `allow-root` or `allow-other` can be used to allow users besides the mounting user to access these files.
2018-11-26 21:16:01 -08:00
Kyle Lacy
a35a24b8b4 mount: Enable "DefaultPermissions" FUSE option by default
This enforces the Unix permissions of the snapshot files within the mounted filesystem, which will only allow users to access snapshot files if they had access to the file outside of the snapshot.
2018-11-26 21:16:01 -08:00
Juergen Hoetzel
df7f72cdde Add support for reading password from external command
This allows reading the password from an password manager (like "pass").

Signed-off-by: Juergen Hoetzel <juergen@archlinux.org>
2018-11-26 20:18:31 +01:00
plumbeo
3edc723bf0 Update 'restic forget --keep-within' documentation and add changelog entry 2018-11-26 14:27:48 +01:00
plumbeo
71891b340c Support time ranges expressed in hours in snapshot retention policies
Make restic forget --keep-within accept time ranges measured in hours and choose
accordingly which snapshots to keep and which to forget. Add relative tests.
2018-11-26 14:27:42 +01:00
Alexander Neumann
6f5c3e57f6 Update vendor/modules.txt 2018-11-25 19:22:57 +01:00
Alexander Neumann
56af0ce370 Add entry to changelog 2018-11-25 19:07:42 +01:00
Alexander Neumann
c9745cd47e gs: Respect bandwidth limiting
In 0dfdc11ed9, accidentally we dropped
using the provided http.RoundTripper, this commits adds it back.

Closes #1989
2018-11-25 18:52:32 +01:00
Alexander Neumann
2434ab2106 Merge pull request 2098 from cdhowie/key-hinting
Add key hinting (#2097)
2018-11-25 17:52:54 +01:00
Chris Howie
1688713400 Add key hinting (#2097) 2018-11-25 09:13:18 -05:00
Alexander Neumann
00597284de cache: Don't return an error for truncated files
Closes #1229
Closes #1328
2018-11-25 14:18:02 +01:00
Alexander Neumann
6dc7cca597 Merge pull request 2086 from frebib/fix-2085
Allow --files-from multiple times
2018-11-25 13:21:29 +01:00
Alexander Neumann
d32c7c2aba Rework changelog for #2085 2018-11-25 12:55:03 +01:00
Joe Groocock
09e9b74cbd Allow --files-from multiple times
Fixes https://github.com/restic/restic/issues/2085
2018-11-25 12:55:03 +01:00
Alexander Neumann
d53595e43c Merge pull request 2088 from garrmcnu/stats-latest-host
stats: Add shorthand flag `-H` for host name filter
2018-11-24 19:05:53 +01:00
Alexander Neumann
0de19cc87f Merge pull request 2095 from plumbeo/parse-location
Use local time for user-provided time of backup
2018-11-24 18:50:12 +01:00
plumbeo
2c9ec07d0b Add changelog entry 2018-11-20 22:18:12 +01:00
plumbeo
a7971a3ece Use local time for user-provided time of backup 2018-11-20 21:28:19 +01:00
Alexander Neumann
4ab0022da8 Add hint which OS are supported
Closes #2016
2018-11-18 12:33:52 +01:00
Garry McNulty
4b3c054257 stats: Add shorthand flag -H for host name filter
The default value of the `--host` flag was set to 'H' (the shorthand
version of the flag), this caused the snapshot lookup to fail.

Also add shorthand `-H` for `backup` command.

Closes #2040
2018-11-14 21:58:31 +00:00
plumbeo
7486bfea5b Extend custom Duration granularity to hours and add tests 2018-11-14 17:27:02 +01:00
Alexander Neumann
c8fc72364a Merge pull request 2081 from restic/fix-2080
backup: Open repository before async status starts
2018-11-11 14:21:47 +01:00
Alexander Neumann
987ef2f4a9 Merge pull request 2082 from restic/fix-2079
dump: Use path instead of filepath
2018-11-11 14:21:37 +01:00
Alexander Neumann
5b95bb7059 Fix error message on Windows 2018-11-11 14:06:32 +01:00
Alexander Neumann
8471a359ee dump: Use path instead of filepath
Some time ago we changed the paths in the repo to always use a slash for
separation, it seems we missed that the `dump` command still uses the
`filepath` package, so on Windows backslashes are used.

Closes #2079
2018-11-10 12:43:11 +01:00
Alexander Neumann
f9422ff4c7 backup: Open repository before async status starts
Closes #2080
2018-11-10 12:38:29 +01:00
Alexander Neumann
c0572ca15f backup: Add warning when patterns do not match any files 2018-11-03 14:51:30 +01:00
Alexander Neumann
a630d69e0c Merge pull request 2070 from restic/display-local-time
Display local time for all commands
2018-11-02 21:16:29 +01:00
Alexander Neumann
20bcd281a3 Add entry to changelog 2018-11-02 20:40:52 +01:00
Alexander Neumann
c012fccd22 Display local time for all commands 2018-11-02 20:36:15 +01:00
Alexander Neumann
920727dd34 Merge pull request #2068 from restic/prune-check-load-error
prune: Correctly handle errors returned by Load()
2018-10-28 22:15:29 +01:00
Alexander Neumann
157d365894 Add entry to CHANGELOG 2018-10-28 21:38:04 +01:00
Alexander Neumann
bfa18ee8ec DownloadAndHash: Check error returned by Load() 2018-10-28 21:28:56 +01:00
Alexander Neumann
890eebf151 Correct summary for #1978 2018-10-28 20:55:49 +01:00
Alexander Neumann
9310cd0cd6 Merge pull request #2056 from restic/recover-data
Add new command 'recover'
2018-10-28 14:26:48 +01:00
Alexander Neumann
9f7ce7ce5a Merge pull request #2066 from restic/fix-list-error
rebuild-index/prune: Correctly handle error listing files
2018-10-28 14:26:40 +01:00
Alexander Neumann
0b600d6cef index.New: Test various error conditions 2018-10-28 14:02:31 +01:00
Alexander Neumann
3ae2a79bdf restic: Use local rand source instead of global one 2018-10-28 14:01:30 +01:00
Alexander Neumann
f7c0893f76 index: Add tests for error conditions 2018-10-28 13:16:36 +01:00
Alexander Neumann
c3de301fc8 index: Use interfaces instead of *repository.Repository 2018-10-28 12:58:34 +01:00
Alexander Neumann
944b446ac0 index: Cancel context for tests 2018-10-28 11:17:04 +01:00
Alexander Neumann
b096fc7abf index: Correctly process errors listing all files
This also removes the now unused `list` and `worker` packages.
2018-10-28 11:16:29 +01:00
Alexander Neumann
d10754e2b4 Merge pull request 2057 from re1/patch-1
Update install instructions for Arch Linux
2018-10-21 20:04:07 +02:00
Alexander Neumann
7ac683c360 rclone: Inject debug logger for HTTP 2018-10-21 19:58:40 +02:00
Markus
6caa9d38ac Update install instructions for Arch Linux
restic has been added to the official community repositories in august 2018.
2018-10-20 13:09:52 +00:00
Alexander Neumann
19fd0f101f Merge pull request 2053 from andyjack/correct-doc-for-self-update
Fix incorrect command name in long doc for self-update
2018-10-20 11:51:13 +02:00
Alexander Neumann
8c91c51d1b Fix timestamps 2018-10-20 11:08:03 +02:00
Alexander Neumann
7e28bf7e97 Add 'recover' command 2018-10-20 11:08:03 +02:00
Alexander Neumann
43d6e426c8 Merge pull request 2054 from gliptak/patch-3
Correct typo
2018-10-20 11:04:49 +02:00
Alexander Neumann
26fc60e7cb Merge pull request 2055 from gliptak/patch-4
Correct ineffassign
2018-10-20 11:04:32 +02:00
Gábor Lipták
e5d7879622 Correct ineffassign
Signed-off-by: Gábor Lipták <gliptak@gmail.com>
2018-10-19 16:58:14 -04:00
Gábor Lipták
d2ee58f2e9 Correct typo 2018-10-18 21:30:14 -04:00
Andy Jack
3f25537a06 Fix incorrect command name in long doc for self-update 2018-10-18 18:45:31 -04:00
Alexander Neumann
d203ae37f4 Merge pull request 2050 from andreasnuesslein/patch-1
tiny formatting fix
2018-10-18 22:31:15 +02:00
Andreas Nüßlein
6eedd66c1a tiny formatting fix
I noticed this discrepancy when trying to parse the output of restic.
2018-10-17 09:41:11 +02:00
Alexander Neumann
e4b39ae553 Merge pull request 2044 from restic/fix-verify
restore: Close files tested with --verify
2018-10-15 21:16:58 +02:00
Alexander Neumann
7cbcb6d318 Merge pull request 2043 from cgroschupp/patch-1
Add ssh binary to docker image to allow sftp repository
2018-10-14 21:43:04 +02:00
Alexander Neumann
c0fca3f50a restore: Close files tested with --verify
Before, the target files were opened once per blob and never closed,
this commit fixes that.
2018-10-14 21:00:14 +02:00
Alexander Neumann
4c2072d875 Merge pull request 1719 from ifedorenko/mt-restorer
new optimized multithreaded restore implementation
2018-10-14 20:29:16 +02:00
Christian Groschupp
92ecca1808 Add ssh binary to docker image to allow sftp repository 2018-10-14 19:56:02 +02:00
Alexander Neumann
7236635cc1 Merge pull request 2042 from restic/fix-2041
self-update: fix path to output file
2018-10-14 19:48:28 +02:00
Alexander Neumann
21a3486ebb Rework changelog entry 2018-10-14 17:39:42 +02:00
Igor Fedorenko
bda8d7722e restorer: Optimize empty file restore
don't create fileInfo structs for empty files. this saves memory.
this also avoids extra serial scan of all fileInfo, which should
make restore faster and more consistent.

Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:39:42 +02:00
Igor Fedorenko
c2bcb764cd restorer: Add a note on hardlink metadata
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:39:42 +02:00
Igor Fedorenko
9e24154ec9 restore: significantly reduce memory footprint
reworked restore error callback to use file location
path instead of much heavier Node. this reduced restore
memory usage by as much as 50% in some of my tests.

Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:39:42 +02:00
Igor Fedorenko
9f3ca97ee8 restore: Chang fileInfo to use snapshot location instead of target path
* uses less memory as common prefix is only stored once
* stepping stone for simpler error callback api, which
  will allow further memory footprint reduction

Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:39:42 +02:00
Igor Fedorenko
32d5ceba87 restore: Fix packcache capacity math with failed downloads
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:39:42 +02:00
Igor Fedorenko
e010f3b884 restore: Fix small memory leak in filesWriter, add tests
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:39:42 +02:00
Alexander Neumann
941202c119 restore: Rename things, match the rest of the project 2018-10-14 17:39:37 +02:00
Alexander Neumann
c021ad2334 restore: Move documentation to godoc 2018-10-14 17:39:35 +02:00
Igor Fedorenko
2b3420820b go mod vendor
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:37:30 +02:00
Igor Fedorenko
da57302fca restore: Removed legacy restore implementation
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:37:30 +02:00
Igor Fedorenko
1869930d95 restore: New optimized multithreaded implementation
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:37:30 +02:00
Igor Fedorenko
1213d8fef4 Cleanup: more realistic restorer test data setup
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-10-14 17:37:30 +02:00
Alexander Neumann
a432b42c81 self-update: Check current version before download 2018-10-14 17:29:46 +02:00
Alexander Neumann
7d0f2eaf24 self-update: Use correct path to restic binary
Closes #2041
2018-10-14 17:29:19 +02:00
Alexander Neumann
41a4d67d93 Merge pull request 1962 from mholt/lsjson
ls: Stream output when using --json option
2018-10-14 15:51:38 +02:00
Alexander Neumann
afde60e433 Merge pull request #2039 from restic/fix-2038
snapshots: Don't print empty line for --compact
2018-10-13 21:24:26 +02:00
Alexander Neumann
d7baa67acb snapshots: Don't print empty line for --compact
Closes #2038
2018-10-13 20:17:34 +02:00
Alexander Neumann
167397c18c Set development version for 0.9.3 2018-10-13 13:48:31 +02:00
Alexander Neumann
be36c5f150 Add version for 0.9.3 2018-10-13 13:48:31 +02:00
Alexander Neumann
9484a14ab2 Update manpages and auto-completion 2018-10-13 13:48:30 +02:00
Alexander Neumann
0f5fc8fb3d Generate CHANGELOG.md for 0.9.3 2018-10-13 13:48:29 +02:00
Alexander Neumann
a5b40e9372 helpers: Use version string in built binaries 2018-10-13 13:48:03 +02:00
Alexander Neumann
c5ec4efe91 Update prepare-release 2018-10-13 13:48:03 +02:00
Alexander Neumann
e64a0e0454 helpers: Don't run sha256sums in build 2018-10-13 13:48:03 +02:00
Alexander Neumann
8b5b031f90 Prepare changelog for 0.9.3 2018-10-13 13:48:03 +02:00
Alexander Neumann
4a2134bbc5 changelog: Rename issue 2018-10-13 13:48:03 +02:00
Alexander Neumann
484844aa1a Document the build and release processes 2018-10-13 13:48:03 +02:00
Alexander Neumann
4ed10239ad doc: Add developer information 2018-10-11 22:37:25 +02:00
Alexander Neumann
c4896ed642 Add build-release-binaries 2018-10-11 22:37:25 +02:00
Alexander Neumann
29aaec383c Move scripts/ to helpers/ 2018-10-11 22:37:25 +02:00
Alexander Neumann
0cb241b7d3 Remove build tag release 2018-10-11 19:40:38 +02:00
Alexander Neumann
de4750b8e0 Add entry to changelog 2018-10-11 19:37:20 +02:00
Alexander Neumann
7b91c40e21 Merge pull request #2033 from j6s/feature.cache-size
Output directory size in cache command
2018-10-11 19:34:57 +02:00
Alexander Neumann
cc9bf02da1 Merge pull request #2036 from SimJoSt/patch-1
doc: cache: fix typo
2018-10-11 19:34:14 +02:00
Joda Stößer
b7959c44d2 doc: cache: fix typo 2018-10-11 14:00:51 +02:00
Johannes Hertenstein
277cba4b32 Catch errors when walking cache directories 2018-10-08 15:47:34 +02:00
Johannes Hertenstein
ed651df19b Use correct method for joining paths 2018-10-08 15:47:08 +02:00
Johannes Hertenstein
641dc65e6e Output directory size in cache command 2018-10-07 14:37:51 +02:00
Alexander Neumann
de9136b29f Merge pull request #2022 from moritzdietz/update-faq
Add example to spot path expansion errors
2018-10-07 12:11:13 +02:00
Moritz Dietz
b36345fd84 Add example to spot path expansion errros 2018-10-07 12:09:46 +02:00
Alexander Neumann
03402c8a04 Merge pull request #2031 from danielb2/latest
use latest instead of newest in forget language
2018-10-06 21:20:21 +02:00
Daniel Bretoi
966e5a5575 use latest instead of newest in forget language 2018-10-06 12:02:22 -07:00
Alexander Neumann
5aa0deeff9 Merge pull request #2026 from gottwald/update-go4docker
Update Go version to 1.11.1 in Docker build script
2018-10-06 13:11:19 +02:00
Alexander Neumann
af4d822380 Merge pull request #2025 from kurin/fixloop
b2: simplify object iteration
2018-10-06 13:01:27 +02:00
Alexander Neumann
fd95b86894 Merge pull request #2029 from j6s/feature.escape-docker-build
Escape subcommand in docker build script
2018-10-06 12:46:08 +02:00
Alexander Neumann
5dbef3712e Merge pull request #2027 from j6s/feature.cache-dir-information
Print base directory with cache command
2018-10-06 12:40:48 +02:00
Johannes Hertenstein
63647e93e4 Escape subcommand in docker build script 2018-10-05 22:13:49 +02:00
Johannes Hertenstein
9b8deb51ba Print base directory with cache command 2018-10-05 21:23:57 +02:00
Ingo Gottwald
2c4b0d975e Update Go version to 1.11.1 in Docker build script
Restic cannot be built with Go 1.8.3 any more, it requires at least Go
1.9.0.
2018-10-05 21:13:28 +02:00
Toby Burress
8ceda538ef b2: simplify object iteration
Blazer is moving to a simpler object list interface, so I'm changing
this here as well.
2018-10-05 11:39:02 -07:00
Alexander Neumann
233596f4bc Merge pull request #2019 from restic/recheck-cache
cache: Recheck before downloading
2018-10-05 12:26:21 +02:00
Alexander Neumann
6712ee8f92 Merge pull request #2020 from j6s/feature.cache-dir-documentation
Add defaults to command line help of --cache-dir
2018-10-05 12:26:12 +02:00
Johannes Hertenstein
0916ff71bd Add defaults to command line help of --cache-dir 2018-10-04 19:50:05 +02:00
Alexander Neumann
5971650f77 cache: Fix recheck logic, remove channel from inProgress 2018-10-04 17:09:43 +02:00
Alexander Neumann
19725954ee cache: Recheck before downloading 2018-10-04 14:31:18 +02:00
Alexander Neumann
b1e1b71bab docker: Base image on latest alpine release 2018-10-03 21:33:13 +02:00
Alexander Neumann
f1799de309 Merge pull request #2018 from restic/fix-1967
Use `--host` for all commands, deprecate --hostname
2018-10-03 21:19:01 +02:00
Alexander Neumann
585a5e3416 Use --host for all commands, deprecate --hostname 2018-10-03 14:12:35 +02:00
Alexander Neumann
b7eeeedc3f Add minimal docs for the top-level package
Closes #173
2018-10-03 13:43:40 +02:00
Alexander Neumann
a20d4bc6b0 Merge pull request #1892 from Stell0/1891
Expand Glob (wildcards character) in paths in file in --files-from
2018-10-03 12:05:55 +02:00
Alexander Neumann
fb31d66951 backup: Improve error message for invalid pattern 2018-10-03 11:12:51 +02:00
Alexander Neumann
33dfbf5c38 Reword changelog 2018-10-03 10:37:35 +02:00
Stefano Fancello
d1df3718b5 Add changelog unreleased file 2018-10-03 10:37:35 +02:00
Stefano Fancello
e2da0a416c Expand Glob (wildcards character) in paths in file in --files-from 2018-10-03 10:37:35 +02:00
Alexander Neumann
0c0a8e3d2b docs: Explain recognizing modified files 2018-10-02 14:21:08 +02:00
Alexander Neumann
0882aca3a8 Add hint for FUSE on FreeBSD 2018-09-26 21:40:43 +02:00
Alexander Neumann
cd41915e10 Merge pull request #2009 from restic/update-minio
Update github.com/minio/minio-go
2018-09-26 14:33:30 +02:00
Alexander Neumann
2effacd444 Update github.com/minio/minio-go
Closes #1918
2018-09-26 14:12:34 +02:00
Alexander Neumann
c6901ff908 Merge pull request #2002 from ifedorenko/dumb-terminals
termstatus: detect and respect dumb terminals on Unix
2018-09-25 13:53:57 +02:00
Alexander Neumann
2f774acce3 Merge pull request #2006 from Calinou/doc-add-scoop-installation
Add Scoop installation method to the documentation
2018-09-25 13:23:28 +02:00
Alexander Neumann
5f8658238c Merge pull request #2005 from Calinou/doc-osx-to-macos
Rename OS X to macOS in the documentation
2018-09-25 13:21:28 +02:00
Hugo Locurcio
2bb1be4d4e Add Scoop installation method to the documentation 2018-09-23 18:42:50 +02:00
Hugo Locurcio
40e0016403 Rename OS X to macOS in the documentation
macOS is the official name since the release of macOS 10.12 (Sierra).
2018-09-23 16:13:34 +02:00
Igor Fedorenko
541d232f1c termstatus: detect and respect dumb terminals on Unix
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
2018-09-21 07:24:41 -04:00
Alexander Neumann
6bc99ce451 Merge pull request #1993 from rfjakob/lchown
restore: suppress lchown errors when not running as root
2018-09-09 20:10:50 +02:00
Jakob Unterwurzacher
e42d2d1da8 restore: suppress lchown errors when not running as root
Like "cp -a" and "rsync -a" do, only report lchown errors if we run
as root.

Like cp from GNU coreutils does, we check Geteuid() to determine if
we are running as root
( http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/copy.c#n3012 ).

On Windows, lchown errors are always reported.

Fixes https://github.com/restic/restic/issues/1766
2018-09-09 15:39:10 +02:00
Alexander Neumann
bd9022962e Merge pull request #1992 from restic/add-go-mod-tidy
Run go mod tidy during CI
2018-09-09 11:03:16 +02:00
Alexander Neumann
91f1b40206 Run go mod tidy during CI 2018-09-09 10:36:27 +02:00
Alexander Neumann
d9b89eead0 Run 'go mod tidy' 2018-09-08 22:12:23 +02:00
Alexander Neumann
5399297de6 Merge pull request #1980 from restic/update-deps
Update dependencies
2018-09-08 21:57:39 +02:00
Alexander Neumann
96f7be5d9b Update dependencies 2018-09-08 21:17:22 +02:00
Alexander Neumann
0922367308 Merge pull request #1991 from restic/debug-1978
scanner: Use context only for cancellation
2018-09-08 20:22:15 +02:00
Alexander Neumann
e2d9900d82 Add entry to CHANGELOG 2018-09-08 18:53:12 +02:00
Alexander Neumann
1140950d7b scanner: Use context only for cancellation
When the scanner is slower than the actual backup, the tomb cancels the
context passed to Scan(), which then returns ctx.Err(). In the end, the
main function prints an error message that is not helpful ("Context
cancelled") and exits with an error code although no error occurred.

The code now ignores the error in the context and just uses it for
cancellation. The scanner is not supposed to return an error anyway.

Closes #1978
2018-09-08 18:53:12 +02:00
Alexander Neumann
6d9c008900 Add template for "regular" issue 2018-09-08 18:00:29 +02:00
Alexander Neumann
b617444158 Test issue template 2018-09-08 17:58:08 +02:00
Alexander Neumann
e588c42646 Move template 2018-09-08 17:55:44 +02:00
Alexander Neumann
14bb2a9005 Add custom issue template 2018-09-08 17:53:52 +02:00
Alexander Neumann
f04d347e7a Merge pull request #1982 from tyll/installation
Update installation instructions
2018-09-05 21:15:38 +02:00
Alexander Neumann
746182c526 Correct name for Apple's desktop OS 2018-09-05 20:41:37 +02:00
Alexander Neumann
08beb7d84c Add section about FreeBSD, move anchor 2018-09-05 20:40:28 +02:00
Alexander Neumann
9795b00f51 Merge pull request #1983 from armhold/vet-cleanup
gh-1385 clean up some errors from 'go vet ./...'
2018-09-05 20:31:11 +02:00
George Armhold
bfc1bc6ee6 clean up some errors from 'go vet ./...' 2018-09-05 08:04:55 -04:00
Till Maas
e9cdcf131c Update installation instructions
- sort sections for different third-party methods
- Mention that Fedora can now just be installed via dnf
- Fix some typos
2018-09-04 14:39:40 +02:00
Alexander Neumann
35e9885e8b Appveyor: correct build cache location 2018-09-02 13:26:02 +02:00
Alexander Neumann
16885529f7 Merge pull request #1973 from restic/announce-new-cache
cache: Print message when new cache is created
2018-09-02 13:00:55 +02:00
Alexander Neumann
3c02eeb5a8 Merge pull request #1920 from restic/support-go111
Support Go 1.11
2018-09-01 11:38:41 +02:00
Alexander Neumann
9e9bb62ad4 Travis: Don't use cached test results 2018-08-31 22:00:47 +02:00
Alexander Neumann
175e630717 Travis: Also cache $GOPATH/pkg/mod 2018-08-31 22:00:47 +02:00
Alexander Neumann
44f38ad049 Travis: Also cache on Darwin 2018-08-31 22:00:47 +02:00
Alexander Neumann
ca928aeae4 Appveyor: Cache Go build cache 2018-08-31 22:00:47 +02:00
Alexander Neumann
27b60a05b4 Travis: Cache Go build artifacts 2018-08-31 22:00:47 +02:00
Alexander Neumann
8af4b331ef Travis: Remove gotestcover 2018-08-31 22:00:47 +02:00
Alexander Neumann
a5a46e4989 Travis: don't use GOPATH for Go >= 1.11 2018-08-31 22:00:47 +02:00
Alexander Neumann
e4cdb0eab3 Travis: Run with -mod=vendor only for Go >= 1.11 2018-08-31 22:00:47 +02:00
Alexander Neumann
e9a764129f Update docs for Go 1.11 2018-08-31 22:00:47 +02:00
Alexander Neumann
65129bde5e Makefile: Try -mod=vendor first 2018-08-31 22:00:47 +02:00
Alexander Neumann
b4beaf807b Travis: Run build.go with -mod=vendor 2018-08-31 22:00:47 +02:00
Alexander Neumann
4734056583 build.go: Major rework, support Go modules 2018-08-31 22:00:47 +02:00
Alexander Neumann
71e0408390 Add entry to changelog 2018-08-31 21:10:26 +02:00
Alexander Neumann
1352a9d848 run_integration_tests: Replace dep with Go modules 2018-08-31 21:10:26 +02:00
Alexander Neumann
e0f68ec2c0 Vendor dependencies with go mod vendor 2018-08-31 21:10:26 +02:00
Alexander Neumann
9c6e0c6eb9 Document gofmt version 2018-08-31 21:10:26 +02:00
Alexander Neumann
4cbc7c4467 Only run gofmt for latest stable version 2018-08-31 21:10:26 +02:00
Alexander Neumann
aaff8803ef Fix formatting for gofmt with Go 1.11 2018-08-31 21:10:26 +02:00
Alexander Neumann
16e20676b6 build.go: Set GOPROXY=off 2018-08-31 21:10:26 +02:00
Alexander Neumann
6cd5f8b7f5 Set GOXPROXY=off for tests, run with -mod=vendor 2018-08-31 21:10:26 +02:00
Alexander Neumann
10c0b8080e Add Go 1.11 to CI tests 2018-08-31 21:10:26 +02:00
Alexander Neumann
d31666d332 build.go: Don't ignore error 2018-08-31 19:51:48 +02:00
Alexander Neumann
6d53e767d5 cache: Print message when new cache is created
Sometimes, users run restic without retaining the local cache
directories. This was reported several times in the past.

Restic will now print a message whenever a new cache directory is
created from scratch (i.e. it did not exist before), so users have a
chance to recognize when the cache is not kept between different runs of
restic.
2018-08-29 22:01:10 +02:00
Alexander Neumann
f1b0bb33dd Merge pull request #1975 from moritzdietz/fix-env-docu
Update B2 env variable information
2018-08-29 22:00:17 +02:00
Moritz Dietz
99ae913414 Update B2 env variable information
* Fixed the B2 environment variables as they had the same description
* Added the variables for the newly introduced Application Key support #1906
2018-08-29 21:05:57 +02:00
Thomas Damgaard
df78896e59 doc: Add list of environment variables 2018-08-28 22:18:47 +02:00
Alexander Neumann
c896751ce2 Merge pull request #1970 from McKael/pull-1780-changelog
Improve changelog entry (pull-1780)
2018-08-28 20:59:10 +02:00
Alexander Neumann
501189625e Merge pull request #1971 from bobsaintcool/doc/fix_man_output
Doc/fix man output
2018-08-28 20:58:21 +02:00
Quentin Bourgeois
a065ada46a Make generated man pages more easy to read with items
Allow Cobra to output a more list items friendly format, this make
reading of the documentation more easily using information from
manpages.
2018-08-27 17:42:54 +02:00
Mikael Berthe
17d6d537e2 Improve changelog entry (pull-1780) 2018-08-27 15:58:39 +02:00
Quentin Bourgeois
5cc224e44a Merge remote-tracking branch 'upsteam/master' 2018-08-26 20:05:02 +02:00
Alexander Neumann
896089976a Fix comment 2018-08-26 19:54:17 +02:00
Quentin Bourgeois
a563f87818 <docs/manual_rest: Fix broken link to restc Design page> 2018-08-26 01:46:38 +02:00
Alexander Neumann
de307ea2ab Merge pull request #1876 from restic/forget-explain
forget: Add --explain
2018-08-25 21:48:44 +02:00
Alexander Neumann
4bc904a527 Merge pull request #1780 from McKael/what-contains
Add options to 'find' for searching IDs (blobs, ...)
2018-08-25 21:46:25 +02:00
Alexander Neumann
5937b5b355 Add entry to changelog 2018-08-20 22:00:23 +02:00
Alexander Neumann
76387b6cd0 Remove old text table implementation 2018-08-20 22:00:23 +02:00
Alexander Neumann
9aa36a37c7 Vendor cmpopts 2018-08-20 21:47:51 +02:00
Alexander Neumann
9fd3796d93 forget: Display reasons why snapshots are kept
This change displays the reasons for keeping a snapshot in the table,
unless `--compact` is specified.
2018-08-20 21:47:51 +02:00
Mikael Berthe
93fa17b53f Add entry to changelog (new find flags) 2018-08-19 23:28:04 +02:00
Alexander Neumann
15ad0e5bc7 walk: Pass parent tree ID to WalkFunc 2018-08-19 23:28:04 +02:00
Mikael Berthe
1f27d17c0d walker.Walk: Pass parent tree-id to WalkFunc 2018-08-19 23:28:04 +02:00
Mikael Berthe
8af918a1e4 find: Add support for multiple patterns or objects 2018-08-19 23:28:04 +02:00
Mikael Berthe
bb5425a1d8 find: Add support for blobs, IDs and packs lookups
With --blob, --tree and --pack, the find command now lists the snapshots
that contain a specific tree or blob, or the snapshots that contain
blobs belonging to a given pack.
It also displays the pack ID a blob belongs to.

A list of IDs can be given, as long as the IDs are all of the same type.
2018-08-19 22:32:30 +02:00
Alexander Neumann
12246969db ui/table: Add small package for writing tables 2018-08-19 21:39:35 +02:00
Matthew Holt
9151eec24e Add changelog entry 2018-08-19 09:14:58 -06:00
Matthew Holt
22475729ce Select specific Node fields for listing 2018-08-19 09:03:47 -06:00
Matthew Holt
04c67d700d ls: Stream output when using --json option 2018-08-19 00:18:43 -06:00
Alexander Neumann
d708d607fa Merge pull request #1953 from kitone/ls-add-json
ls: Add JSON output support for restic ls cmd
2018-08-18 15:31:15 +02:00
Alexander Neumann
46f71f4c22 Improve changelog entry 2018-08-18 15:14:52 +02:00
kitone
48cc2f2188 fix: switch struct_type value to lower case 2018-08-18 14:57:50 +02:00
kitone
bd6e7c934c add changelog entry 2018-08-18 14:57:50 +02:00
kitone
7925217e25 ls: Add JSON output support for restic ls cmd 2018-08-18 14:57:50 +02:00
Alexander Neumann
401a564486 Merge pull request #1961 from mholt/statsoutput
stats: Show what was scanned and scanning mode used
2018-08-18 14:29:14 +02:00
Alexander Neumann
31176d212b doc: Add explanation for "processed" vs "added" 2018-08-18 14:26:57 +02:00
Matthew Holt
2d89311d49 stats: Show what was scanned and scanning mode used 2018-08-17 17:15:30 -06:00
Alexander Neumann
5a25ad1972 Update version in build.go 2018-08-17 21:17:26 +02:00
Alexander Neumann
79d3a18b31 release.go: Add version to global.go
Closes #1958
2018-08-17 21:17:10 +02:00
Alexander Neumann
89f17847ad Merge pull request #1955 from restic/fix-prune-1954
prune: Fix calculation for removed bytes
2018-08-14 22:30:59 +02:00
Alexander Neumann
1ab5703404 prune: Fix calculation for removed bytes 2018-08-14 22:06:05 +02:00
Alexander Neumann
49d95e9a50 Merge pull request #1949 from restic/add-self-update
Add command self-update
2018-08-13 22:02:34 +02:00
Alexander Neumann
7dff1a08d0 Merge pull request #1950 from ldelouw/master
Add RPM SPEC file to create restic packages on Fedora and RHEL
2018-08-13 22:00:18 +02:00
Alexander Neumann
5fee36fa84 Merge pull request #1941 from mholt/lsfilter
ls: Implement directory filter, optionally subfolders
2018-08-13 21:58:32 +02:00
Luc de Louw
b0211dff49 Small change for RHEL6 which does not know about the %license macro 2018-08-13 21:39:04 +02:00
Luc de Louw
0f6d21cf84 Add the SPEC file restic.spec to build RPMs
Tested on Fedora 28, RHEL 6 and 7
2018-08-13 21:39:04 +02:00
Alexander Neumann
10b5cf8f32 Add self-update to the docs 2018-08-12 23:56:06 +02:00
Alexander Neumann
ad5aec3f3b Add entry to changelog 2018-08-12 23:56:01 +02:00
Alexander Neumann
6e1a3987b7 Add 'self-update' command
This commit adds a command called `self-update` which downloads the
latest released version of restic from GitHub and replacing the current
binary with it. It does not rely on any external program (so it'll work
everywhere), but still verifies the GPG signature using the embedded GPG
public key.

By default, the `self-update` command is hidden behind the `selfupdate`
built tag, which is only set when restic is built using `build.go`. The
reason for this is that downstream distributions will then not include
the command by default, so users are encouraged to use the
platform-specific distribution mechanism.
2018-08-12 23:34:47 +02:00
Alexander Neumann
9630398e3b ls: Rework and simplify logic
This commit introduces two functions: withinDir() and
approachingMatchingTree()

Both bind the list of directories with a closure, so we don't need to
iterate over the list in the function passed to Walk(). This reduces the
indentation level and since we can just use return, we don't need the
breaks any more.

The case that len(dirs) == 0 can also be handled by the functions with a
return, which saves another indentation level.

The main function body of the function passed to Walk() was reduced to
three cases:

 * Within one of the dirs: Print the node, and if recursive operation is
   requested, directly return, so the walker continues recursive
   traversal

 * Approaching one of the dirs: don't print anything, but continue
   recursive traversal.

 * Nothing of the two: abort walking this branch of the tree.
2018-08-12 23:13:34 +02:00
Alexander Neumann
7e34de4c29 ls: Add comments 2018-08-12 22:18:44 +02:00
Alexander Neumann
ace5cc4ed3 ls: Only skip directory nodes
Special case for Walk(): When SkipDir is returned for a non-dir node,
the remaining nodes for the current tree are skipped. We don't want
that.
2018-08-12 22:02:59 +02:00
Alexander Neumann
7f617cfd7f ls: Use nodepath for filter 2018-08-12 22:01:38 +02:00
Alexander Neumann
0deb4e5994 ls: Check dirs before opening the repository
Users get feedback instantly, and before any expensive network calls
have been made.
2018-08-12 21:59:57 +02:00
Alexander Neumann
6b9dde3ce8 Merge pull request #1912 from askielboe/select-funcs
Support for different kinds of select functions
2018-08-12 19:26:36 +02:00
Alexander Neumann
c145b618d4 Add entry to changelog 2018-08-12 17:51:12 +02:00
Andreas Skielboe
b07bb3d8c3 Reject files excluded by name before calling lstat to improve scan speed
Adds a SelectByName method to the archive and scanner which only require
the filename as input, and can thus be run before calling lstat on the
file. Can speed up scanning significantly if a lot of filename excludes
are used.
2018-08-12 17:51:12 +02:00
Alexander Neumann
9b513312e2 Merge pull request #1946 from restic/fix-1945
Remove truncated files from cache
2018-08-12 17:23:56 +02:00
Alexander Neumann
bf26a3ed57 Merge pull request #1948 from restic/update-build-go
Update build.go
2018-08-12 17:18:11 +02:00
Alexander Neumann
77a8d931b8 Update build.go 2018-08-12 15:44:13 +02:00
Matthew Holt
11ce572894 Fix bug where some folder listings were empty 2018-08-11 17:17:43 -06:00
Matthew Holt
7a468d1226 Speed up nonrecursive queries; include exact filter match 2018-08-11 16:18:09 -06:00
Matthew Holt
00e2fd8b5f Apply feedback and use SkipNode 2018-08-11 15:25:22 -06:00
Alexander Neumann
0f83fea007 cache: Fix test for new behavior
Accessing beyond the end of the file now removes the file from the cache
because it is assumed to be truncated. Usually, this means that the data
is fetched directly from the backend instead.
2018-08-11 23:11:51 +02:00
Alexander Neumann
04f7c054cd Add entry to changelog 2018-08-11 22:54:22 +02:00
Alexander Neumann
5dd0df0162 cache: Remove files from cache which are too small 2018-08-11 22:47:01 +02:00
Alexander Neumann
abc923f693 Merge pull request #1942 from mholt/statserr
stats: Improve error message for bad snapshot ID (fixes #1933)
2018-08-11 14:26:24 +02:00
Matthew Holt
ac3bd6b2eb Replace Exitf with errors.Fatalf 2018-08-10 22:15:33 -06:00
Matthew Holt
156d85a29b Minor fixes/tweaks; add docs 2018-08-10 22:10:02 -06:00
Matthew Holt
8c146eac4b ls: Implement directory filter, optionally subfolders 2018-08-10 21:41:38 -06:00
Matthew Holt
6f5b0f3622 stat: Improve error message for bad snapshot ID (fixes #1933) 2018-08-08 16:49:36 -06:00
526 changed files with 50356 additions and 117508 deletions

27
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,27 @@
<!--
Welcome! If you have a question or are unsure if you should open an issue,
please use the forum instead!
https://forum.restic.net
The forum is a better place for questions about restic or general suggestions
and topics, e.g. usage or documentation questions! This issue tracker is mainly
for tracking bugs and feature requests directly relating to the development of
the software itself, rather than the project.
Thanks for understanding, and for contributing to the project!
-->
Output of `restic version`
--------------------------
<!--
Please add the version of restic you're currently using here, this helps us
later to see what has changed in restic when we revisit this issue after some
time.
-->
Describe the issue
------------------

1
.gitignore vendored
View File

@@ -1,3 +1,2 @@
/restic
/.vagrant
/doc/_build

View File

@@ -6,15 +6,35 @@ matrix:
- os: linux
go: "1.9.x"
env: RESTIC_TEST_FUSE=0 RESTIC_TEST_CLOUD_BACKENDS=0 RESTIC_BUILD_SOLARIS=0
cache:
directories:
- $HOME/.cache/go-build
- $HOME/gopath/pkg/mod
- os: linux
go: "1.10.x"
env: RESTIC_TEST_FUSE=0 RESTIC_TEST_CLOUD_BACKENDS=0
cache:
directories:
- $HOME/.cache/go-build
- $HOME/gopath/pkg/mod
# only run fuse and cloud backends tests on Travis for the latest Go on Linux
- os: linux
go: "1.10.x"
go: "1.11.x"
sudo: true
cache:
directories:
- $HOME/.cache/go-build
- $HOME/gopath/pkg/mod
- os: osx
go: "1.10.x"
go: "1.11.x"
env: RESTIC_TEST_FUSE=0 RESTIC_TEST_CLOUD_BACKENDS=0
cache:
directories:
- $HOME/Library/Caches/go-build
- $HOME/gopath/pkg/mod
branches:
only:
@@ -38,4 +58,4 @@ script:
- go run run_integration_tests.go
after_success:
- bash <(curl -s https://codecov.io/bash) -f all.cov
- test -r all.cov && bash <(curl -s https://codecov.io/bash) -f all.cov

View File

@@ -1,3 +1,302 @@
Changelog for restic 0.9.4 (2019-01-06)
=======================================
The following sections list the changes in restic 0.9.4 relevant to
restic users. The changes are ordered by importance.
Summary
-------
* Fix #1989: Google Cloud Storage: Respect bandwidth limit
* Fix #2040: Add host name filter shorthand flag for `stats` command
* Fix #2068: Correctly return error loading data
* Fix #2095: Consistently use local time for snapshots times
* Enh #1605: Concurrent restore
* Enh #2089: Increase granularity of the "keep within" retention policy
* Enh #2097: Add key hinting
* Enh #2017: Mount: Enforce FUSE Unix permissions with allow-other
* Enh #2070: Make all commands display timestamps in local time
* Enh #2085: Allow --files-from to be specified multiple times
* Enh #2094: Run command to get password
Details
-------
* Bugfix #1989: Google Cloud Storage: Respect bandwidth limit
The GCS backend did not respect the bandwidth limit configured, a previous commit
accidentally removed support for it.
https://github.com/restic/restic/issues/1989
https://github.com/restic/restic/pull/2100
* Bugfix #2040: Add host name filter shorthand flag for `stats` command
The default value for `--host` flag was set to 'H' (the shorthand version of the flag), this
caused the lookup for the latest snapshot to fail.
Add shorthand flag `-H` for `--host` (with empty default so if these flags are not specified the
latest snapshot will not filter by host name).
Also add shorthand `-H` for `backup` command.
https://github.com/restic/restic/issues/2040
* Bugfix #2068: Correctly return error loading data
In one case during `prune` and `check`, an error loading data from the backend is not returned
properly. This is now corrected.
https://github.com/restic/restic/issues/1999#issuecomment-433737921
https://github.com/restic/restic/pull/2068
* Bugfix #2095: Consistently use local time for snapshots times
By default snapshots created with restic backup were set to local time, but when the --time flag
was used the provided timestamp was parsed as UTC. With this change all snapshots times are set
to local time.
https://github.com/restic/restic/pull/2095
* Enhancement #1605: Concurrent restore
This change significantly improves restore performance, especially when using
high-latency remote repositories like B2.
The implementation now uses several concurrent threads to download and process multiple
remote files concurrently. To further reduce restore time, each remote file is downloaded
using a single repository request.
https://github.com/restic/restic/issues/1605
https://github.com/restic/restic/pull/1719
* Enhancement #2089: Increase granularity of the "keep within" retention policy
The `keep-within` option of the `forget` command now accepts time ranges with an hourly
granularity. For example, running `restic forget --keep-within 3d12h` will keep all the
snapshots made within three days and twelve hours from the time of the latest snapshot.
https://github.com/restic/restic/issues/2089
https://github.com/restic/restic/pull/2090
* Enhancement #2097: Add key hinting
Added a new option `--key-hint` and corresponding environment variable `RESTIC_KEY_HINT`.
The key hint is a key ID to try decrypting first, before other keys in the repository.
This change will benefit repositories with many keys; if the correct key hint is supplied then
restic only needs to check one key. If the key hint is incorrect (the key does not exist, or the
password is incorrect) then restic will check all keys, as usual.
https://github.com/restic/restic/issues/2097
* Enhancement #2017: Mount: Enforce FUSE Unix permissions with allow-other
The fuse mount (`restic mount`) now lets the kernel check the permissions of the files within
snapshots (this is done through the `DefaultPermissions` FUSE option) when the option
`--allow-other` is specified.
To restore the old behavior, we've added the `--no-default-permissions` option. This allows
all users that have access to the mount point to access all files within the snapshots.
https://github.com/restic/restic/pull/2017
* Enhancement #2070: Make all commands display timestamps in local time
Restic used to drop the timezone information from displayed timestamps, it now converts
timestamps to local time before printing them so the times can be easily compared to.
https://github.com/restic/restic/pull/2070
* Enhancement #2085: Allow --files-from to be specified multiple times
Before, restic took only the last file specified with `--files-from` into account, this is now
corrected.
https://github.com/restic/restic/issues/2085
https://github.com/restic/restic/pull/2086
* Enhancement #2094: Run command to get password
We've added the `--password-command` option which allows specifying a command that restic
runs every time the password for the repository is needed, so it can be integrated with a
password manager or keyring. The option can also be set via the environment variable
`$RESTIC_PASSWORD_COMMAND`.
https://github.com/restic/restic/pull/2094
Changelog for restic 0.9.3 (2018-10-13)
=======================================
The following sections list the changes in restic 0.9.3 relevant to
restic users. The changes are ordered by importance.
Summary
-------
* Fix #1935: Remove truncated files from cache
* Fix #1978: Do not return an error when the scanner is slower than backup
* Enh #1766: Restore: suppress lchown errors when not running as root
* Enh #1909: Reject files/dirs by name first
* Enh #1940: Add directory filter to ls command
* Enh #1967: Use `--host` everywhere
* Enh #2028: Display size of cache directories
* Enh #1777: Improve the `find` command
* Enh #1876: Display reason why forget keeps snapshots
* Enh #1891: Accept glob in paths loaded via --files-from
* Enh #1920: Vendor dependencies with Go 1.11 Modules
* Enh #1949: Add new command `self-update`
* Enh #1953: Ls: Add JSON output support for restic ls cmd
* Enh #1962: Stream JSON output for ls command
Details
-------
* Bugfix #1935: Remove truncated files from cache
When a file in the local cache is truncated, and restic tries to access data beyond the end of the
(cached) file, it used to return an error "EOF". This is now fixed, such truncated files are
removed and the data is fetched directly from the backend.
https://github.com/restic/restic/issues/1935
* Bugfix #1978: Do not return an error when the scanner is slower than backup
When restic makes a backup, there's a background task called "scanner" which collects
information on how many files and directories are to be saved, in order to display progress
information to the user. When the backup finishes faster than the scanner, it is aborted
because the result is not needed any more. This logic contained a bug, where quitting the
scanner process was treated as an error, and caused restic to print an unhelpful error message
("context canceled").
https://github.com/restic/restic/issues/1978
https://github.com/restic/restic/pull/1991
* Enhancement #1766: Restore: suppress lchown errors when not running as root
Like "cp" and "rsync" do, restic now only reports errors for changing the ownership of files
during restore if it is run as root, on non-Windows operating systems. On Windows, the error
is reported as usual.
https://github.com/restic/restic/issues/1766
* Enhancement #1909: Reject files/dirs by name first
The current scanner/archiver code had an architectural limitation: it always ran the
`lstat()` system call on all files and directories before a decision to include/exclude the
file/dir was made. This lead to a lot of unnecessary system calls for items that could have been
rejected by their name or path only.
We've changed the archiver/scanner implementation so that it now first rejects by name/path,
and only runs the system call on the remaining items. This reduces the number of `lstat()`
system calls a lot (depending on the exclude settings).
https://github.com/restic/restic/issues/1909
https://github.com/restic/restic/pull/1912
* Enhancement #1940: Add directory filter to ls command
The ls command can now be filtered by directories, so that only files in the given directories
will be shown. If the --recursive flag is specified, then ls will traverse subfolders and list
their files as well.
It used to be possible to specify multiple snapshots, but that has been replaced by only one
snapshot and the possibility of specifying multiple directories.
Specifying directories constrains the walk, which can significantly speed up the listing.
https://github.com/restic/restic/issues/1940
https://github.com/restic/restic/pull/1941
* Enhancement #1967: Use `--host` everywhere
We now use the flag `--host` for all commands which need a host name, using `--hostname` (e.g.
for `restic backup`) still works, but will print a deprecation warning. Also, add the short
option `-H` where possible.
https://github.com/restic/restic/issues/1967
* Enhancement #2028: Display size of cache directories
The `cache` command now by default shows the size of the individual cache directories. It can be
disabled with `--no-size`.
https://github.com/restic/restic/issues/2028
https://github.com/restic/restic/pull/2033
* Enhancement #1777: Improve the `find` command
We've updated the `find` command to support multiple patterns.
`restic find` is now able to list the snapshots containing a specific tree or blob, or even the
snapshots that contain blobs belonging to a given pack. A list of IDs can be given, as long as they
all have the same type.
The command `find` can also display the pack IDs the blobs belong to, if the `--show-pack-id`
flag is provided.
https://github.com/restic/restic/issues/1777
https://github.com/restic/restic/pull/1780
* Enhancement #1876: Display reason why forget keeps snapshots
We've added a column to the list of snapshots `forget` keeps which details the reasons to keep a
particuliar snapshot. This makes debugging policies for forget much easier. Please remember
to always try things out with `--dry-run`!
https://github.com/restic/restic/pull/1876
* Enhancement #1891: Accept glob in paths loaded via --files-from
Before that, behaviour was different if paths were appended to command line or from a file,
because wild card characters were expanded by shell if appended to command line, but not
expanded if loaded from file.
https://github.com/restic/restic/issues/1891
* Enhancement #1920: Vendor dependencies with Go 1.11 Modules
Until now, we've used `dep` for managing dependencies, we've now switch to using Go modules.
For users this does not change much, only if you want to compile restic without downloading
anything with Go 1.11, then you need to run: `go build -mod=vendor build.go`
https://github.com/restic/restic/pull/1920
* Enhancement #1949: Add new command `self-update`
We have added a new command called `self-update` which downloads the latest released version
of restic from GitHub and replaces the current binary with it. It does not rely on any external
program (so it'll work everywhere), but still verifies the GPG signature using the embedded
GPG public key.
By default, the `self-update` command is hidden behind the `selfupdate` built tag, which is
only set when restic is built using `build.go` (including official releases). The reason for
this is that downstream distributions will then not include the command by default, so users
are encouraged to use the platform-specific distribution mechanism.
https://github.com/restic/restic/pull/1949
* Enhancement #1953: Ls: Add JSON output support for restic ls cmd
We've implemented listing files in the repository with JSON as output, just pass `--json` as an
option to `restic ls`. This makes the output of the command machine readable.
https://github.com/restic/restic/pull/1953
* Enhancement #1962: Stream JSON output for ls command
The `ls` command now supports JSON output with the global `--json` flag, and this change
streams out JSON messages one object at a time rather than en entire array buffered in memory
before encoding. The advantage is it allows large listings to be handled efficiently.
Two message types are printed: snapshots and nodes. A snapshot object will precede node
objects which belong to that snapshot. The `struct_type` field can be used to determine which
kind of message an object is.
https://github.com/restic/restic/pull/1962
Changelog for restic 0.9.2 (2018-08-06)
=======================================

View File

@@ -46,12 +46,15 @@ Remember, the easier it is for us to reproduce the bug, the earlier it will be
corrected!
In addition, you can compile restic with debug support by running
`go run build.go -tags debug` and instructing it to create a debug log by
setting the environment variable `DEBUG_LOG` to a file, e.g. like this:
`go run -mod=vendor build.go -tags debug` and instructing it to create a debug
log by setting the environment variable `DEBUG_LOG` to a file, e.g. like this:
$ export DEBUG_LOG=/tmp/restic-debug.log
$ restic backup ~/work
For Go < 1.11, you need to remove the `-mod=vendor` option from the build
command.
Please be aware that the debug log file will contain potentially sensitive
things like file and directory names, so please either redact it before
uploading it somewhere or post only the parts that are really relevant.
@@ -60,9 +63,37 @@ uploading it somewhere or post only the parts that are really relevant.
Development Environment
=======================
In order to compile restic with the `go` tool directly, it needs to be checked
out at the right path within a `GOPATH`. The concept of a `GOPATH` is explained
in ["How to write Go code"](https://golang.org/doc/code.html).
The repository contains several sets of directories with code: `cmd/` and
`internal/` contain the code written for restic, whereas `vendor/` contains
copies of libraries restic depends on. The libraries are managed with the
command `go mod vendor`.
Go >= 1.11
----------
For Go version 1.11 or later, you should clone the repo (without having
`$GOPATH` set) and `cd` into the directory:
$ unset GOPATH
$ git clone https://github.com/restic/restic
$ cd restic
Then use the `go` tool to build restic:
$ go build ./cmd/restic
$ ./restic version
restic 0.9.2-dev (compiled manually) compiled with go1.11 on linux/amd64
You can run all tests with the following command:
$ go test ./...
Go < 1.11
---------
In order to compile restic with Go before 1.11, it needs to be checked out at
the right path within a `GOPATH`. The concept of a `GOPATH` is explained in
["How to write Go code"](https://golang.org/doc/code.html).
If you do not have a directory with Go code yet, executing the following
instructions in your shell will create one for you and check out the restic
@@ -83,12 +114,7 @@ You can then build restic as follows:
The following commands can be used to run all the tests:
$ go test ./cmd/... ./internal/...
The repository contains two sets of directories with code: `cmd/` and
`internal/` contain the code written for restic, whereas `vendor/` contains
copies of libraries restic depends on. The libraries are managed with the
[`dep`](https://github.com/golang/dep) tool.
$ go test ./...
Providing Patches
=================
@@ -141,13 +167,14 @@ run
gofmt -w **/*.go
in the project root directory before committing. Installing the script
`fmt-check` from https://github.com/edsrzf/gofmt-git-hook locally as a
pre-commit hook checks formatting before committing automatically, just copy
this script to `.git/hooks/pre-commit`.
in the project root directory before committing. For each Pull Request, the
formatting is tested with `gofmt` for the latest stable version of Go.
Installing the script `fmt-check` from https://github.com/edsrzf/gofmt-git-hook
locally as a pre-commit hook checks formatting before committing automatically,
just copy this script to `.git/hooks/pre-commit`.
For each pull request, several different systems run the integration tests on
Linux, OS X and Windows. We won't merge any code that does not pass all tests
Linux, macOS and Windows. We won't merge any code that does not pass all tests
for all systems, so when a tests fails, try to find out what's wrong and fix
it. If you need help on this, please leave a comment in the pull request, and
we'll be glad to assist. Having a PR with failing integration tests is nothing

474
Gopkg.lock generated
View File

@@ -1,474 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
digest = "1:94e9caf404409a2990cfd22aca37d758494c098eff3e2c37fda1abed862e74dd"
name = "bazil.org/fuse"
packages = [
".",
"fs",
"fuseutil",
]
pruneopts = "UT"
revision = "65cc252bf6691cb3c7014bcb2c8dc29de91e3a7e"
[[projects]]
digest = "1:5c3894b2aa4d6bead0ceeea6831b305d62879c871780e7b76296ded1b004bc57"
name = "cloud.google.com/go"
packages = ["compute/metadata"]
pruneopts = "UT"
revision = "aad3f485ee528456e0768f20397b4d9dd941e755"
version = "v0.25.0"
[[projects]]
digest = "1:46ea9487304f4b3c787f54483ecb13a338d686dcd670db0ab1a112ed0ae2128e"
name = "github.com/Azure/azure-sdk-for-go"
packages = [
"storage",
"version",
]
pruneopts = "UT"
revision = "4e8cbbfb1aeab140cd0fa97fd16b64ee18c3ca6a"
version = "v19.1.0"
[[projects]]
digest = "1:27d0cd1a78fc836f7c0f07749d029a5f7895c84ad066187b08b70e9d1830098e"
name = "github.com/Azure/go-autorest"
packages = [
"autorest",
"autorest/adal",
"autorest/azure",
"autorest/date",
"logger",
"version",
]
pruneopts = "UT"
revision = "dd94e014aaf16d1df746762e392aa201c1b4c461"
version = "v10.15.0"
[[projects]]
digest = "1:2209584c0f7c9b68c23374e659357ab546e1b70eec2761f03280f69a8fd23d77"
name = "github.com/cenkalti/backoff"
packages = ["."]
pruneopts = "UT"
revision = "2ea60e5f094469f9e65adb9cd103795b73ae743e"
version = "v2.0.0"
[[projects]]
digest = "1:7cb4fdca4c251b3ef8027c90ea35f70c7b661a593b9eeae34753c65499098bb1"
name = "github.com/cpuguy83/go-md2man"
packages = ["md2man"]
pruneopts = "UT"
revision = "20f5889cbdc3c73dbd2862796665e7c465ade7d1"
version = "v1.0.8"
[[projects]]
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
pruneopts = "UT"
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
version = "v3.2.0"
[[projects]]
branch = "master"
digest = "1:6f9339c912bbdda81302633ad7e99a28dfa5a639c864061f1929510a9a64aa74"
name = "github.com/dustin/go-humanize"
packages = ["."]
pruneopts = "UT"
revision = "9f541cc9db5d55bce703bd99987c9d5cb8eea45e"
[[projects]]
digest = "1:c7edfbb6320d6a93240d663dc52bca92bed4c116abe54c35679eec4e7cc2bd77"
name = "github.com/elithrar/simple-scrypt"
packages = ["."]
pruneopts = "UT"
revision = "d150773194090feb6c897805a7bcea8d49544e2c"
version = "v1.3.0"
[[projects]]
digest = "1:fe8a03a8222d5b913f256972933d26d24ad7c8286692a42943bc01633cc8fce3"
name = "github.com/go-ini/ini"
packages = ["."]
pruneopts = "UT"
revision = "358ee7663966325963d4e8b2e1fbd570c5195153"
version = "v1.38.1"
[[projects]]
digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861"
name = "github.com/golang/protobuf"
packages = ["proto"]
pruneopts = "UT"
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
[[projects]]
digest = "1:2e3c336fc7fde5c984d2841455a658a6d626450b1754a854b3b32e7a8f49a07a"
name = "github.com/google/go-cmp"
packages = [
"cmp",
"cmp/internal/diff",
"cmp/internal/function",
"cmp/internal/value",
]
pruneopts = "UT"
revision = "3af367b6b30c263d47e8895973edcca9a49cf029"
version = "v0.2.0"
[[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
pruneopts = "UT"
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
digest = "1:190ff84d9b2ed6589088f178cba8edb4b8ecb334df4572421fb016be1ac20463"
name = "github.com/juju/ratelimit"
packages = ["."]
pruneopts = "UT"
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
version = "1.0.1"
[[projects]]
digest = "1:9cedee824c21326bd26950bd9e1ffe9dc4e7ca03dc8634d0e6f954ee6a383172"
name = "github.com/kr/fs"
packages = ["."]
pruneopts = "UT"
revision = "1455def202f6e05b95cc7bfc7e8ae67ae5141eba"
version = "v0.1.0"
[[projects]]
digest = "1:1faa76bd9bffce9c25eaca0597afb67bd05a21ae57fe4378154ce8855ef163d1"
name = "github.com/kurin/blazer"
packages = [
"b2",
"base",
"internal/b2assets",
"internal/b2types",
"internal/blog",
"x/window",
]
pruneopts = "UT"
revision = "caf65aa76491dc533bac68ad3243ce72fa4e0a0a"
version = "v0.5.1"
[[projects]]
digest = "1:4e878df5f4e9fd625bf9c9aac77ef7cbfa4a74c01265505527c23470c0e40300"
name = "github.com/marstr/guid"
packages = ["."]
pruneopts = "UT"
revision = "8bd9a64bf37eb297b492a4101fb28e80ac0b290f"
version = "v1.1.0"
[[projects]]
digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = "UT"
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
digest = "1:95c73c666919be2843b955eafc83f58c136312b74f79c703152f4c4a95fd64dc"
name = "github.com/minio/minio-go"
packages = [
".",
"pkg/credentials",
"pkg/encrypt",
"pkg/s3signer",
"pkg/s3utils",
"pkg/set",
]
pruneopts = "UT"
revision = "70799fe8dae6ecfb6c7d7e9e048fce27f23a1992"
version = "v6.0.5"
[[projects]]
branch = "master"
digest = "1:8eb17c2ec4df79193ae65b621cd1c0c4697db3bc317fe6afdc76d7f2746abd05"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
pruneopts = "UT"
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
[[projects]]
digest = "1:928de5172dd3563964d1b88a4ee3775cf72e16f1efabb482ab6d0e0bab86ee69"
name = "github.com/ncw/swift"
packages = ["."]
pruneopts = "UT"
revision = "b2a7479cf26fa841ff90dd932d0221cb5c50782d"
version = "v1.0.39"
[[projects]]
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = "UT"
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
digest = "1:cfa0d7741863a0e1d30e0ccdd4b48a96a471cdb47892303de8b92c3713af3e77"
name = "github.com/pkg/profile"
packages = ["."]
pruneopts = "UT"
revision = "5b67d428864e92711fcbd2f8629456121a56d91f"
version = "v1.2.1"
[[projects]]
digest = "1:23ed92ba5d90a2dfe817f3895027ccef796e79c30be5125d48e17afdcc395d73"
name = "github.com/pkg/sftp"
packages = ["."]
pruneopts = "UT"
revision = "57673e38ea946592a59c26592b7e6fbda646975b"
version = "v1.8.0"
[[projects]]
digest = "1:0d67664e93e366f072ac9672feea29bfc63c9f90f005e9e8a0df1954153f5a14"
name = "github.com/pkg/xattr"
packages = ["."]
pruneopts = "UT"
revision = "ae385d07bb53f092fcc7daaf738d8513df084931"
version = "v0.3.1"
[[projects]]
digest = "1:13ecc4000f49cf0aa3ee56fffcc93119c8edffacfff08674c80d2757d8c33a83"
name = "github.com/restic/chunker"
packages = ["."]
pruneopts = "UT"
revision = "db83917be3b88cc307464b7d8a221c173e34a0db"
version = "v0.2.0"
[[projects]]
digest = "1:8bc629776d035c003c7814d4369521afe67fdb8efc4b5f66540d29343b98cf23"
name = "github.com/russross/blackfriday"
packages = ["."]
pruneopts = "UT"
revision = "55d61fa8aa702f59229e6cff85793c22e580eaf5"
version = "v1.5.1"
[[projects]]
digest = "1:274f67cb6fed9588ea2521ecdac05a6d62a8c51c074c1fccc6a49a40ba80e925"
name = "github.com/satori/go.uuid"
packages = ["."]
pruneopts = "UT"
revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
version = "v1.2.0"
[[projects]]
digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
version = "v1.0.6"
[[projects]]
digest = "1:e01b05ba901239c783dfe56450bcde607fc858908529868259c9a8765dc176d0"
name = "github.com/spf13/cobra"
packages = [
".",
"doc",
]
pruneopts = "UT"
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3"
[[projects]]
digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "UT"
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
version = "v1.0.1"
[[projects]]
branch = "master"
digest = "1:eefb1f49ec07e71206d4c9ea1a3e634cad331c2180733e4121b8ae39e8e92ecb"
name = "golang.org/x/crypto"
packages = [
"argon2",
"blake2b",
"curve25519",
"ed25519",
"ed25519/internal/edwards25519",
"internal/chacha20",
"internal/subtle",
"pbkdf2",
"poly1305",
"scrypt",
"ssh",
"ssh/terminal",
]
pruneopts = "UT"
revision = "c126467f60eb25f8f27e5a981f32a87e3965053f"
[[projects]]
branch = "master"
digest = "1:8356aa7bdcb10a210b814b64ff76d61de7c36ac4cb6263de3af5e3e2e546956d"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
]
pruneopts = "UT"
revision = "32f9bdbd7df18e8641d215e7ea68be88b971feb0"
[[projects]]
branch = "master"
digest = "1:bea0314c10bd362ab623af4880d853b5bad3b63d0ab9945c47e461b8d04203ed"
name = "golang.org/x/oauth2"
packages = [
".",
"google",
"internal",
"jws",
"jwt",
]
pruneopts = "UT"
revision = "3d292e4d0cdc3a0113e6d207bb137145ef1de42f"
[[projects]]
branch = "master"
digest = "1:39ebcc2b11457b703ae9ee2e8cca0f68df21969c6102cb3b705f76cca0ea0239"
name = "golang.org/x/sync"
packages = ["errgroup"]
pruneopts = "UT"
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
[[projects]]
branch = "master"
digest = "1:a220a85c72a6cb7339c412cb2b117019a7fd94007cdfffb3b5b1d058227a2bf8"
name = "golang.org/x/sys"
packages = [
"cpu",
"unix",
"windows",
]
pruneopts = "UT"
revision = "bd9dbc187b6e1dacfdd2722a87e83093c2d7bd6e"
[[projects]]
digest = "1:e5a8511f063c38c51ab9ab80e718e9149f692652aeb4e393a8c020dd1bf38ca2"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"encoding",
"encoding/internal",
"encoding/internal/identifier",
"encoding/unicode",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"internal/utf8internal",
"language",
"runes",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
]
pruneopts = "UT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
digest = "1:fb983acae7bd9c3ed9aadc1b1241d9e559ed21dbf84c17a0dda663ca169ccd69"
name = "google.golang.org/api"
packages = [
"gensupport",
"googleapi",
"googleapi/internal/uritemplates",
"storage/v1",
]
pruneopts = "UT"
revision = "31ca0e01cd791f07750cb23fc99327721f753290"
[[projects]]
digest = "1:c8907869850adaa8bd7631887948d0684f3787d0912f1c01ab72581a6c34432e"
name = "google.golang.org/appengine"
packages = [
".",
"internal",
"internal/app_identity",
"internal/base",
"internal/datastore",
"internal/log",
"internal/modules",
"internal/remote_api",
"internal/urlfetch",
"urlfetch",
]
pruneopts = "UT"
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
[[projects]]
branch = "v2"
digest = "1:5bb148b78468350091db2ffbb2370f35cc6dcd74d9378a31b1c7b86ff7528f08"
name = "gopkg.in/tomb.v2"
packages = ["."]
pruneopts = "UT"
revision = "d5d1b5820637886def9eef33e03a27a9f166942c"
[[projects]]
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"bazil.org/fuse",
"bazil.org/fuse/fs",
"github.com/Azure/azure-sdk-for-go/storage",
"github.com/cenkalti/backoff",
"github.com/elithrar/simple-scrypt",
"github.com/google/go-cmp/cmp",
"github.com/juju/ratelimit",
"github.com/kurin/blazer/b2",
"github.com/mattn/go-isatty",
"github.com/minio/minio-go",
"github.com/minio/minio-go/pkg/credentials",
"github.com/ncw/swift",
"github.com/pkg/errors",
"github.com/pkg/profile",
"github.com/pkg/sftp",
"github.com/pkg/xattr",
"github.com/restic/chunker",
"github.com/spf13/cobra",
"github.com/spf13/cobra/doc",
"github.com/spf13/pflag",
"golang.org/x/crypto/poly1305",
"golang.org/x/crypto/scrypt",
"golang.org/x/crypto/ssh/terminal",
"golang.org/x/net/context",
"golang.org/x/net/context/ctxhttp",
"golang.org/x/net/http2",
"golang.org/x/oauth2/google",
"golang.org/x/sync/errgroup",
"golang.org/x/sys/unix",
"golang.org/x/text/encoding/unicode",
"google.golang.org/api/googleapi",
"google.golang.org/api/storage/v1",
"gopkg.in/tomb.v2",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,25 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[prune]
unused-packages = true
go-tests = true

View File

@@ -3,7 +3,7 @@
all: restic
restic:
go run build.go
go run -mod=vendor build.go || go run build.go
clean:
rm -f restic

View File

@@ -3,7 +3,7 @@
Introduction
------------
restic is a backup program that is fast, efficient and secure.
restic is a backup program that is fast, efficient and secure. It supports the three major operating systems (Linux, macOS, Windows) and a few smaller ones (FreeBSD, OpenBSD).
For detailed usage and installation instructions check out the `documentation <https://restic.readthedocs.io/en/latest>`__.

View File

@@ -1 +1 @@
0.9.2
0.9.4

View File

@@ -7,6 +7,9 @@ branches:
only:
- master
cache:
- '%LocalAppData%\go-build'
init:
- ps: >-
$app = Get-WmiObject -Class Win32_Product -Filter "Vendor = 'http://golang.org'"
@@ -17,8 +20,8 @@ init:
install:
- rmdir c:\go /s /q
- appveyor DownloadFile https://dl.google.com/go/go1.10.windows-amd64.msi
- msiexec /i go1.10.windows-amd64.msi /q
- appveyor DownloadFile https://dl.google.com/go/go1.11.windows-amd64.msi
- msiexec /i go1.11.windows-amd64.msi /q
- go version
- go env
- appveyor DownloadFile http://sourceforge.netcologne.de/project/gnuwin32/tar/1.13-1/tar-1.13-1-bin.zip -FileName tar.zip
@@ -26,4 +29,4 @@ install:
- set PATH=bin/;%PATH%
build_script:
- go run run_integration_tests.go
- go run -mod=vendor run_integration_tests.go

325
build.go
View File

@@ -1,3 +1,18 @@
// Description
//
// This program aims to make building Go programs for end users easier by just
// calling it with `go run`, without having to setup a GOPATH.
//
// For Go < 1.11, it'll create a new GOPATH in a temporary directory, then run
// `go build` on the package configured as Main in the Config struct.
//
// For Go >= 1.11 if the file go.mod is present, it'll use Go modules and not
// setup a GOPATH. It builds the package configured as Main in the Config
// struct with `go build -mod=vendor` to use the vendored dependencies.
// The variable GOPROXY is set to `off` so that no network calls are made. All
// files are copied to a temporary directory before `go build` is called within
// that directory.
// BSD 2-Clause License
//
// Copyright (c) 2016-2018, Alexander Neumann <alexander@bumpern.de>
@@ -37,7 +52,6 @@ import (
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
@@ -46,23 +60,22 @@ import (
// config contains the configuration for the program to build.
var config = Config{
Name: "restic", // name of the program executable and directory
Namespace: "github.com/restic/restic", // subdir of GOPATH, e.g. "github.com/foo/bar"
Main: "github.com/restic/restic/cmd/restic", // package name for the main package
Tests: []string{ // tests to run
"github.com/restic/restic/internal/...",
"github.com/restic/restic/cmd/...",
},
MinVersion: GoVersion{Major: 1, Minor: 9, Patch: 0}, // minimum Go version supported
Name: "restic", // name of the program executable and directory
Namespace: "github.com/restic/restic", // subdir of GOPATH, e.g. "github.com/foo/bar"
Main: "./cmd/restic", // package name for the main package
DefaultBuildTags: []string{"selfupdate"}, // specify build tags which are always used
Tests: []string{"./..."}, // tests to run
MinVersion: GoVersion{Major: 1, Minor: 9, Patch: 0}, // minimum Go version supported
}
// Config configures the build.
type Config struct {
Name string
Namespace string
Main string
Tests []string
MinVersion GoVersion
Name string
Namespace string
Main string
DefaultBuildTags []string
Tests []string
MinVersion GoVersion
}
var (
@@ -71,41 +84,12 @@ var (
runTests bool
enableCGO bool
enablePIE bool
goVersion = ParseGoVersion(runtime.Version())
)
// specialDir returns true if the file begins with a special character ('.' or '_').
func specialDir(name string) bool {
if name == "." {
return false
}
base := filepath.Base(name)
if base == "vendor" || base[0] == '_' || base[0] == '.' {
return true
}
return false
}
// excludePath returns true if the file should not be copied to the new GOPATH.
func excludePath(name string) bool {
ext := path.Ext(name)
if ext == ".go" || ext == ".s" || ext == ".h" {
return false
}
parentDir := filepath.Base(filepath.Dir(name))
if parentDir == "testdata" {
return false
}
return true
}
// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
// to dst/prefix/, so calling
// copy all Go files in src to dst, creating directories on the fly, so calling
//
// updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
// copy("/tmp/gopath/src/github.com/restic/restic", "/home/u/restic")
//
// with "/home/u/restic" containing the file "foo.go" yields the following tree
// at "/tmp/gopath":
@@ -116,19 +100,15 @@ func excludePath(name string) bool {
// └── restic
// └── restic
// └── foo.go
func updateGopath(dst, src, prefix string) error {
verbosePrintf("copy contents of %v to %v\n", src, filepath.Join(dst, prefix))
func copy(dst, src string) error {
verbosePrintf("copy contents of %v to %v\n", src, dst)
return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
if name == src {
return err
}
if specialDir(name) {
if fi.IsDir() {
return filepath.SkipDir
}
return nil
if name == ".git" {
return filepath.SkipDir
}
if err != nil {
@@ -139,17 +119,13 @@ func updateGopath(dst, src, prefix string) error {
return nil
}
if excludePath(name) {
return nil
}
intermediatePath, err := filepath.Rel(src, name)
if err != nil {
return err
}
fileSrc := filepath.Join(src, intermediatePath)
fileDst := filepath.Join(dst, "src", prefix, intermediatePath)
fileDst := filepath.Join(dst, intermediatePath)
return copyFile(fileDst, fileSrc)
})
@@ -164,6 +140,15 @@ func directoryExists(dirname string) bool {
return stat.IsDir()
}
func fileExists(filename string) bool {
stat, err := os.Stat(filename)
if err != nil && os.IsNotExist(err) {
return false
}
return stat.Mode().IsRegular()
}
// copyFile creates dst from src, preserving file attributes and timestamps.
func copyFile(dst, src string) error {
fi, err := os.Stat(src)
@@ -183,30 +168,34 @@ func copyFile(dst, src string) error {
fdst, err := os.Create(dst)
if err != nil {
_ = fsrc.Close()
return err
}
if _, err = io.Copy(fdst, fsrc); err != nil {
_, err = io.Copy(fdst, fsrc)
if err != nil {
_ = fsrc.Close()
_ = fdst.Close()
return err
}
if err == nil {
err = fsrc.Close()
err = fdst.Close()
if err != nil {
_ = fsrc.Close()
return err
}
if err == nil {
err = fdst.Close()
err = fsrc.Close()
if err != nil {
return err
}
if err == nil {
err = os.Chmod(dst, fi.Mode())
err = os.Chmod(dst, fi.Mode())
if err != nil {
return err
}
if err == nil {
err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
}
return nil
return os.Chtimes(dst, fi.ModTime(), fi.ModTime())
}
// die prints the message with fmt.Fprintf() to stderr and exits with an error
@@ -222,7 +211,7 @@ func showUsage(output io.Writer) {
fmt.Fprintf(output, "OPTIONS:\n")
fmt.Fprintf(output, " -v --verbose output more messages\n")
fmt.Fprintf(output, " -t --tags specify additional build tags\n")
fmt.Fprintf(output, " -k --keep-gopath do not remove the GOPATH after build\n")
fmt.Fprintf(output, " -k --keep-tempdir do not remove the temporary directory after build\n")
fmt.Fprintf(output, " -T --test run tests\n")
fmt.Fprintf(output, " -o --output set output file name\n")
fmt.Fprintf(output, " --enable-cgo use CGO to link against libc\n")
@@ -241,11 +230,20 @@ func verbosePrintf(message string, args ...interface{}) {
fmt.Printf("build: "+message, args...)
}
// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
// present).
// cleanEnv returns a clean environment with GOPATH, GOBIN and GO111MODULE
// removed (if present).
func cleanEnv() (env []string) {
removeKeys := map[string]struct{}{
"GOPATH": struct{}{},
"GOBIN": struct{}{},
"GO111MODULE": struct{}{},
}
for _, v := range os.Environ() {
if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
data := strings.SplitN(v, "=", 2)
name := data[0]
if _, ok := removeKeys[name]; ok {
continue
}
@@ -256,17 +254,17 @@ func cleanEnv() (env []string) {
}
// build runs "go build args..." with GOPATH set to gopath.
func build(cwd string, ver GoVersion, goos, goarch, goarm, gopath string, args ...string) error {
func build(cwd string, env map[string]string, args ...string) error {
a := []string{"build"}
if ver.AtLeast(GoVersion{1, 10, 0}) {
if goVersion.AtLeast(GoVersion{1, 10, 0}) {
verbosePrintf("Go version is at least 1.10, using new syntax for -gcflags\n")
// use new prefix
a = append(a, "-asmflags", fmt.Sprintf("all=-trimpath=%s", gopath))
a = append(a, "-gcflags", fmt.Sprintf("all=-trimpath=%s", gopath))
a = append(a, "-asmflags", fmt.Sprintf("all=-trimpath=%s", cwd))
a = append(a, "-gcflags", fmt.Sprintf("all=-trimpath=%s", cwd))
} else {
a = append(a, "-asmflags", fmt.Sprintf("-trimpath=%s", gopath))
a = append(a, "-gcflags", fmt.Sprintf("-trimpath=%s", gopath))
a = append(a, "-asmflags", fmt.Sprintf("-trimpath=%s", cwd))
a = append(a, "-gcflags", fmt.Sprintf("-trimpath=%s", cwd))
}
if enablePIE {
a = append(a, "-buildmode=pie")
@@ -274,9 +272,9 @@ func build(cwd string, ver GoVersion, goos, goarch, goarm, gopath string, args .
a = append(a, args...)
cmd := exec.Command("go", a...)
cmd.Env = append(cleanEnv(), "GOPATH="+gopath, "GOARCH="+goarch, "GOOS="+goos)
if goarm != "" {
cmd.Env = append(cmd.Env, "GOARM="+goarm)
cmd.Env = append(cleanEnv(), "GOPROXY=off")
for k, v := range env {
cmd.Env = append(cmd.Env, k+"="+v)
}
if !enableCGO {
cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
@@ -285,20 +283,30 @@ func build(cwd string, ver GoVersion, goos, goarch, goarm, gopath string, args .
cmd.Dir = cwd
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
verbosePrintf("go %s\n", a)
verbosePrintf("chdir %q\n", cwd)
verbosePrintf("go %q\n", a)
return cmd.Run()
}
// test runs "go test args..." with GOPATH set to gopath.
func test(cwd, gopath string, args ...string) error {
args = append([]string{"test"}, args...)
func test(cwd string, env map[string]string, args ...string) error {
args = append([]string{"test", "-count", "1"}, args...)
cmd := exec.Command("go", args...)
cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
cmd.Env = append(cleanEnv(), "GOPROXY=off")
for k, v := range env {
cmd.Env = append(cmd.Env, k+"="+v)
}
if !enableCGO {
cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
}
cmd.Dir = cwd
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
verbosePrintf("go %s\n", args)
verbosePrintf("chdir %q\n", cwd)
verbosePrintf("go %q\n", args)
return cmd.Run()
}
@@ -446,22 +454,24 @@ func (v GoVersion) String() string {
}
func main() {
ver := ParseGoVersion(runtime.Version())
if !ver.AtLeast(config.MinVersion) {
fmt.Fprintf(os.Stderr, "%s detected, this program requires at least %s\n", ver, config.MinVersion)
if !goVersion.AtLeast(config.MinVersion) {
fmt.Fprintf(os.Stderr, "%s detected, this program requires at least %s\n", goVersion, config.MinVersion)
os.Exit(1)
}
buildTags := []string{}
buildTags := config.DefaultBuildTags
skipNext := false
params := os.Args[1:]
targetGOOS := runtime.GOOS
targetGOARCH := runtime.GOARCH
targetGOARM := ""
goEnv := map[string]string{}
buildEnv := map[string]string{
"GOOS": runtime.GOOS,
"GOARCH": runtime.GOARCH,
"GOARM": "",
}
gopath := ""
tempdir := ""
var outputFilename string
@@ -481,13 +491,13 @@ func main() {
die("-t given but no tag specified")
}
skipNext = true
buildTags = strings.Split(params[i+1], " ")
buildTags = append(buildTags, strings.Split(params[i+1], " ")...)
case "-o", "--output":
skipNext = true
outputFilename = params[i+1]
case "--tempdir":
skipNext = true
gopath = params[i+1]
tempdir = params[i+1]
case "-T", "--test":
runTests = true
case "--enable-cgo":
@@ -496,13 +506,13 @@ func main() {
enablePIE = true
case "--goos":
skipNext = true
targetGOOS = params[i+1]
buildEnv["GOOS"] = params[i+1]
case "--goarch":
skipNext = true
targetGOARCH = params[i+1]
buildEnv["GOARCH"] = params[i+1]
case "--goarm":
skipNext = true
targetGOARM = params[i+1]
buildEnv["GOARM"] = params[i+1]
case "-h":
showUsage(os.Stdout)
return
@@ -513,12 +523,7 @@ func main() {
}
}
verbosePrintf("detected Go version %v\n", ver)
if len(buildTags) == 0 {
verbosePrintf("adding build-tag release\n")
buildTags = []string{"release"}
}
verbosePrintf("detected Go version %v\n", goVersion)
for i := range buildTags {
buildTags[i] = strings.TrimSpace(buildTags[i])
@@ -531,50 +536,16 @@ func main() {
die("Getwd(): %v\n", err)
}
if gopath == "" {
gopath, err = ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
if err != nil {
die("TempDir(): %v\n", err)
}
}
verbosePrintf("create GOPATH at %v\n", gopath)
if err = updateGopath(gopath, root, config.Namespace); err != nil {
die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
}
vendor := filepath.Join(root, "vendor")
if directoryExists(vendor) {
if err = updateGopath(gopath, vendor, filepath.Join(config.Namespace, "vendor")); err != nil {
die("copying files from %v to %v failed: %v\n", root, gopath, err)
}
}
defer func() {
if !keepGopath {
verbosePrintf("remove %v\n", gopath)
if err = os.RemoveAll(gopath); err != nil {
die("remove GOPATH at %s failed: %v\n", err)
}
} else {
verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
}
}()
if outputFilename == "" {
outputFilename = config.Name
if targetGOOS == "windows" {
if buildEnv["GOOS"] == "windows" {
outputFilename += ".exe"
}
}
cwd, err := os.Getwd()
if err != nil {
die("Getwd() returned %v\n", err)
}
output := outputFilename
if !filepath.IsAbs(output) {
output = filepath.Join(cwd, output)
output = filepath.Join(root, output)
}
version := getVersion()
@@ -585,13 +556,65 @@ func main() {
ldflags := "-s -w " + constants.LDFlags()
verbosePrintf("ldflags: %s\n", ldflags)
args := []string{
"-tags", strings.Join(buildTags, " "),
"-ldflags", ldflags,
"-o", output, config.Main,
var (
buildArgs []string
testArgs []string
)
mainPackage := config.Main
if strings.HasPrefix(mainPackage, config.Namespace) {
mainPackage = strings.Replace(mainPackage, config.Namespace, "./", 1)
}
err = build(filepath.Join(gopath, "src"), ver, targetGOOS, targetGOARCH, targetGOARM, gopath, args...)
buildTarget := filepath.FromSlash(mainPackage)
buildCWD := ""
if goVersion.AtLeast(GoVersion{1, 11, 0}) && fileExists("go.mod") {
verbosePrintf("Go >= 1.11 and 'go.mod' found, building with modules\n")
buildCWD = root
buildArgs = append(buildArgs, "-mod=vendor")
testArgs = append(testArgs, "-mod=vendor")
} else {
if tempdir == "" {
tempdir, err = ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
if err != nil {
die("TempDir(): %v\n", err)
}
}
verbosePrintf("Go < 1.11 or 'go.mod' not found, create GOPATH at %v\n", tempdir)
targetdir := filepath.Join(tempdir, "src", filepath.FromSlash(config.Namespace))
if err = copy(targetdir, root); err != nil {
die("copying files from %v to %v/src failed: %v\n", root, tempdir, err)
}
defer func() {
if !keepGopath {
verbosePrintf("remove %v\n", tempdir)
if err = os.RemoveAll(tempdir); err != nil {
die("remove GOPATH at %s failed: %v\n", tempdir, err)
}
} else {
verbosePrintf("leaving temporary GOPATH at %v\n", tempdir)
}
}()
buildCWD = targetdir
goEnv["GOPATH"] = tempdir
buildEnv["GOPATH"] = tempdir
}
verbosePrintf("environment:\n go: %v\n build: %v\n", goEnv, buildEnv)
buildArgs = append(buildArgs,
"-tags", strings.Join(buildTags, " "),
"-ldflags", ldflags,
"-o", output, buildTarget,
)
err = build(buildCWD, buildEnv, buildArgs...)
if err != nil {
die("build failed: %v\n", err)
}
@@ -599,7 +622,9 @@ func main() {
if runTests {
verbosePrintf("running tests\n")
err = test(cwd, gopath, config.Tests...)
testArgs = append(testArgs, config.Tests...)
err = test(buildCWD, goEnv, testArgs...)
if err != nil {
die("running tests failed: %v\n", err)
}

View File

@@ -0,0 +1,7 @@
Enhancement: restore: suppress lchown errors when not running as root
Like "cp" and "rsync" do, restic now only reports errors for changing
the ownership of files during restore if it is run as root, on non-Windows
operating systems. On Windows, the error is reported as usual.
https://github.com/restic/restic/issues/1766

View File

@@ -0,0 +1,14 @@
Enhancement: Reject files/dirs by name first
The current scanner/archiver code had an architectural limitation: it always
ran the `lstat()` system call on all files and directories before a decision to
include/exclude the file/dir was made. This lead to a lot of unnecessary system
calls for items that could have been rejected by their name or path only.
We've changed the archiver/scanner implementation so that it now first rejects
by name/path, and only runs the system call on the remaining items. This
reduces the number of `lstat()` system calls a lot (depending on the exclude
settings).
https://github.com/restic/restic/issues/1909
https://github.com/restic/restic/pull/1912

View File

@@ -0,0 +1,8 @@
Bugfix: Remove truncated files from cache
When a file in the local cache is truncated, and restic tries to access data
beyond the end of the (cached) file, it used to return an error "EOF". This is
now fixed, such truncated files are removed and the data is fetched directly
from the backend.
https://github.com/restic/restic/issues/1935

View File

@@ -0,0 +1,15 @@
Enhancement: Add directory filter to ls command
The ls command can now be filtered by directories, so that only files in the
given directories will be shown. If the --recursive flag is specified, then
ls will traverse subfolders and list their files as well.
It used to be possible to specify multiple snapshots, but that has been
replaced by only one snapshot and the possibility of specifying multiple
directories.
Specifying directories constrains the walk, which can significantly speed up
the listing.
https://github.com/restic/restic/issues/1940
https://github.com/restic/restic/pull/1941

View File

@@ -0,0 +1,7 @@
Enhancement: Use `--host` everywhere
We now use the flag `--host` for all commands which need a host name, using
`--hostname` (e.g. for `restic backup`) still works, but will print a
deprecation warning. Also, add the short option `-H` where possible.
https://github.com/restic/restic/issues/1967

View File

@@ -0,0 +1,12 @@
Bugfix: Do not return an error when the scanner is slower than backup
When restic makes a backup, there's a background task called "scanner" which
collects information on how many files and directories are to be saved, in
order to display progress information to the user. When the backup finishes
faster than the scanner, it is aborted because the result is not needed any
more. This logic contained a bug, where quitting the scanner process was
treated as an error, and caused restic to print an unhelpful error message
("context canceled").
https://github.com/restic/restic/issues/1978
https://github.com/restic/restic/pull/1991

View File

@@ -0,0 +1,7 @@
Enhancement: Display size of cache directories
The `cache` command now by default shows the size of the individual cache
directories. It can be disabled with `--no-size`.
https://github.com/restic/restic/issues/2028
https://github.com/restic/restic/pull/2033

View File

@@ -0,0 +1,13 @@
Enhancement: Improve the `find` command
We've updated the `find` command to support multiple patterns.
`restic find` is now able to list the snapshots containing a specific tree
or blob, or even the snapshots that contain blobs belonging to a given pack.
A list of IDs can be given, as long as they all have the same type.
The command `find` can also display the pack IDs the blobs belong to, if
the `--show-pack-id` flag is provided.
https://github.com/restic/restic/issues/1777
https://github.com/restic/restic/pull/1780

View File

@@ -0,0 +1,7 @@
Enhancement: Display reason why forget keeps snapshots
We've added a column to the list of snapshots `forget` keeps which details the
reasons to keep a particuliar snapshot. This makes debugging policies for
forget much easier. Please remember to always try things out with `--dry-run`!
https://github.com/restic/restic/pull/1876

View File

@@ -0,0 +1,7 @@
Enhancement: Accept glob in paths loaded via --files-from
Before that, behaviour was different if paths were appended to command line or
from a file, because wild card characters were expanded by shell if appended to
command line, but not expanded if loaded from file.
https://github.com/restic/restic/issues/1891

View File

@@ -0,0 +1,8 @@
Enhancement: Vendor dependencies with Go 1.11 Modules
Until now, we've used `dep` for managing dependencies, we've now switch to
using Go modules. For users this does not change much, only if you want to
compile restic without downloading anything with Go 1.11, then you need to run:
`go build -mod=vendor build.go`
https://github.com/restic/restic/pull/1920

View File

@@ -0,0 +1,15 @@
Enhancement: Add new command `self-update`
We have added a new command called `self-update` which downloads the
latest released version of restic from GitHub and replaces the current
binary with it. It does not rely on any external program (so it'll work
everywhere), but still verifies the GPG signature using the embedded GPG
public key.
By default, the `self-update` command is hidden behind the `selfupdate`
built tag, which is only set when restic is built using `build.go` (including
official releases). The reason for this is that downstream distributions will
then not include the command by default, so users are encouraged to use the
platform-specific distribution mechanism.
https://github.com/restic/restic/pull/1949

View File

@@ -0,0 +1,7 @@
Enhancement: ls: Add JSON output support for restic ls cmd
We've implemented listing files in the repository with JSON as output, just
pass `--json` as an option to `restic ls`. This makes the output of the command
machine readable.
https://github.com/restic/restic/pull/1953

View File

@@ -0,0 +1,13 @@
Enhancement: Stream JSON output for ls command
The `ls` command now supports JSON output with the global `--json`
flag, and this change streams out JSON messages one object at a time
rather than en entire array buffered in memory before encoding. The
advantage is it allows large listings to be handled efficiently.
Two message types are printed: snapshots and nodes. A snapshot
object will precede node objects which belong to that snapshot.
The `struct_type` field can be used to determine which kind of
message an object is.
https://github.com/restic/restic/pull/1962

View File

@@ -0,0 +1,11 @@
Enhancement: Concurrent restore
This change significantly improves restore performance, especially
when using high-latency remote repositories like B2.
The implementation now uses several concurrent threads to download and process
multiple remote files concurrently. To further reduce restore time, each remote
file is downloaded using a single repository request.
https://github.com/restic/restic/issues/1605
https://github.com/restic/restic/pull/1719

View File

@@ -0,0 +1,7 @@
Bugfix: Google Cloud Storage: Respect bandwidth limit
The GCS backend did not respect the bandwidth limit configured, a previous
commit accidentally removed support for it.
https://github.com/restic/restic/issues/1989
https://github.com/restic/restic/pull/2100

View File

@@ -0,0 +1,11 @@
Bugfix: Add host name filter shorthand flag for `stats` command
The default value for `--host` flag was set to 'H' (the shorthand version of
the flag), this caused the lookup for the latest snapshot to fail.
Add shorthand flag `-H` for `--host` (with empty default so if these flags
are not specified the latest snapshot will not filter by host name).
Also add shorthand `-H` for `backup` command.
https://github.com/restic/restic/issues/2040

View File

@@ -0,0 +1,9 @@
Enhancement: increase granularity of the "keep within" retention policy
The `keep-within` option of the `forget` command now accepts time ranges with
an hourly granularity. For example, running `restic forget --keep-within 3d12h`
will keep all the snapshots made within three days and twelve hours from the
time of the latest snapshot.
https://github.com/restic/restic/issues/2089
https://github.com/restic/restic/pull/2090

View File

@@ -0,0 +1,12 @@
Enhancement: Add key hinting
Added a new option `--key-hint` and corresponding environment variable
`RESTIC_KEY_HINT`. The key hint is a key ID to try decrypting first, before
other keys in the repository.
This change will benefit repositories with many keys; if the correct key hint
is supplied then restic only needs to check one key. If the key hint is
incorrect (the key does not exist, or the password is incorrect) then restic
will check all keys, as usual.
https://github.com/restic/restic/issues/2097

View File

@@ -0,0 +1,11 @@
Enhancement: mount: Enforce FUSE Unix permissions with allow-other
The fuse mount (`restic mount`) now lets the kernel check the permissions of
the files within snapshots (this is done through the `DefaultPermissions` FUSE
option) when the option `--allow-other` is specified.
To restore the old behavior, we've added the `--no-default-permissions` option.
This allows all users that have access to the mount point to access all
files within the snapshots.
https://github.com/restic/restic/pull/2017

View File

@@ -0,0 +1,6 @@
Bugfix: Correctly return error loading data
In one case during `prune` and `check`, an error loading data from the backend is not returned properly. This is now corrected.
https://github.com/restic/restic/pull/2068
https://github.com/restic/restic/issues/1999#issuecomment-433737921

View File

@@ -0,0 +1,7 @@
Enhancement: Make all commands display timestamps in local time
Restic used to drop the timezone information from displayed timestamps, it now
converts timestamps to local time before printing them so the times can be
easily compared to.
https://github.com/restic/restic/pull/2070

View File

@@ -0,0 +1,7 @@
Enhancement: Allow --files-from to be specified multiple times
Before, restic took only the last file specified with `--files-from` into
account, this is now corrected.
https://github.com/restic/restic/issues/2085
https://github.com/restic/restic/pull/2086

View File

@@ -0,0 +1,8 @@
Enhancement: Run command to get password
We've added the `--password-command` option which allows specifying a command
that restic runs every time the password for the repository is needed, so it
can be integrated with a password manager or keyring. The option can also be
set via the environment variable `$RESTIC_PASSWORD_COMMAND`.
https://github.com/restic/restic/pull/2094

View File

@@ -0,0 +1,7 @@
Bugfix: consistently use local time for snapshots times
By default snapshots created with restic backup were set to local time,
but when the --time flag was used the provided timestamp was parsed as
UTC. With this change all snapshots times are set to local time.
https://github.com/restic/restic/pull/2095

View File

@@ -4,8 +4,10 @@ import (
"bufio"
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"time"
@@ -32,19 +34,23 @@ The "backup" command creates a new snapshot and saves the files and directories
given as the arguments.
`,
PreRun: func(cmd *cobra.Command, args []string) {
if backupOptions.Hostname == "" {
if backupOptions.Host == "" {
hostname, err := os.Hostname()
if err != nil {
debug.Log("os.Hostname() returned err: %v", err)
return
}
backupOptions.Hostname = hostname
backupOptions.Host = hostname
}
},
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
if backupOptions.Stdin && backupOptions.FilesFrom == "-" {
return errors.Fatal("cannot use both `--stdin` and `--files-from -`")
if backupOptions.Stdin {
for _, filename := range backupOptions.FilesFrom {
if filename == "-" {
return errors.Fatal("cannot use both `--stdin` and `--files-from -`")
}
}
}
var t tomb.Tomb
@@ -72,8 +78,8 @@ type BackupOptions struct {
Stdin bool
StdinFilename string
Tags []string
Hostname string
FilesFrom string
Host string
FilesFrom []string
TimeStamp string
WithAtime bool
}
@@ -94,8 +100,12 @@ func init() {
f.BoolVar(&backupOptions.Stdin, "stdin", false, "read backup from stdin")
f.StringVar(&backupOptions.StdinFilename, "stdin-filename", "stdin", "file name to use when reading from stdin")
f.StringArrayVar(&backupOptions.Tags, "tag", nil, "add a `tag` for the new snapshot (can be specified multiple times)")
f.StringVar(&backupOptions.Hostname, "hostname", "", "set the `hostname` for the snapshot manually. To prevent an expensive rescan use the \"parent\" flag")
f.StringVar(&backupOptions.FilesFrom, "files-from", "", "read the files to backup from file (can be combined with file args)")
f.StringVarP(&backupOptions.Host, "host", "H", "", "set the `hostname` for the snapshot manually. To prevent an expensive rescan use the \"parent\" flag")
f.StringVar(&backupOptions.Host, "hostname", "", "set the `hostname` for the snapshot manually")
f.MarkDeprecated("hostname", "use --host")
f.StringArrayVar(&backupOptions.FilesFrom, "files-from", nil, "read the files to backup from file (can be combined with file args/can be specified multiple times)")
f.StringVar(&backupOptions.TimeStamp, "time", "", "time of the backup (ex. '2012-11-01 22:08:41') (default: now)")
f.BoolVar(&backupOptions.WithAtime, "with-atime", false, "store the atime for all files and directories")
}
@@ -169,12 +179,16 @@ func readLinesFromFile(filename string) ([]string, error) {
// Check returns an error when an invalid combination of options was set.
func (opts BackupOptions) Check(gopts GlobalOptions, args []string) error {
if opts.FilesFrom == "-" && gopts.password == "" {
return errors.Fatal("unable to read password from stdin when data is to be read from stdin, use --password-file or $RESTIC_PASSWORD")
if gopts.password == "" {
for _, filename := range opts.FilesFrom {
if filename == "-" {
return errors.Fatal("unable to read password from stdin when data is to be read from stdin, use --password-file or $RESTIC_PASSWORD")
}
}
}
if opts.Stdin {
if opts.FilesFrom != "" {
if len(opts.FilesFrom) > 0 {
return errors.Fatal("--stdin and --files-from cannot be used together")
}
@@ -186,18 +200,9 @@ func (opts BackupOptions) Check(gopts GlobalOptions, args []string) error {
return nil
}
// collectRejectFuncs returns a list of all functions which may reject data
// from being saved in a snapshot
func collectRejectFuncs(opts BackupOptions, repo *repository.Repository, targets []string) (fs []RejectFunc, err error) {
// allowed devices
if opts.ExcludeOtherFS && !opts.Stdin {
f, err := rejectByDevice(targets)
if err != nil {
return nil, err
}
fs = append(fs, f)
}
// collectRejectByNameFuncs returns a list of all functions which may reject data
// from being saved in a snapshot based on path only
func collectRejectByNameFuncs(opts BackupOptions, repo *repository.Repository, targets []string) (fs []RejectByNameFunc, err error) {
// exclude restic cache
if repo.Cache != nil {
f, err := rejectResticCache(repo)
@@ -237,6 +242,21 @@ func collectRejectFuncs(opts BackupOptions, repo *repository.Repository, targets
return fs, nil
}
// collectRejectFuncs returns a list of all functions which may reject data
// from being saved in a snapshot based on path and file info
func collectRejectFuncs(opts BackupOptions, repo *repository.Repository, targets []string) (fs []RejectFunc, err error) {
// allowed devices
if opts.ExcludeOtherFS && !opts.Stdin {
f, err := rejectByDevice(targets)
if err != nil {
return nil, err
}
fs = append(fs, f)
}
return fs, nil
}
// readExcludePatternsFromFiles reads all exclude files and returns the list of
// exclude patterns. For each line, leading and trailing white space is removed
// and comment lines are ignored. For each remaining pattern, environment
@@ -290,15 +310,31 @@ func collectTargets(opts BackupOptions, args []string) (targets []string, err er
return nil, nil
}
fromfile, err := readLinesFromFile(opts.FilesFrom)
if err != nil {
return nil, err
var lines []string
for _, file := range opts.FilesFrom {
fromfile, err := readLinesFromFile(file)
if err != nil {
return nil, err
}
// expand wildcards
for _, line := range fromfile {
var expanded []string
expanded, err := filepath.Glob(line)
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("pattern: %s", line))
}
if len(expanded) == 0 {
Warnf("pattern %q does not match any files, skipping\n", line)
}
lines = append(lines, expanded...)
}
}
// merge files from files-from into normal args so we can reuse the normal
// args checks and have the ability to use both files-from and args at the
// same time
args = append(args, fromfile...)
args = append(args, lines...)
if len(args) == 0 && !opts.Stdin {
return nil, errors.Fatal("nothing to backup, please specify target files/dirs")
}
@@ -327,7 +363,7 @@ func findParentSnapshot(ctx context.Context, repo restic.Repository, opts Backup
// Find last snapshot to set it as parent, if not already set
if !opts.Force && parentID == nil {
id, err := restic.FindLatestSnapshot(ctx, repo, targets, []restic.TagList{}, opts.Hostname)
id, err := restic.FindLatestSnapshot(ctx, repo, targets, []restic.TagList{}, opts.Host)
if err == nil {
parentID = &id
} else if err != restic.ErrNoSnapshotFound {
@@ -351,7 +387,7 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
timeStamp := time.Now()
if opts.TimeStamp != "" {
timeStamp, err = time.Parse(TimeFormat, opts.TimeStamp)
timeStamp, err = time.ParseInLocation(TimeFormat, opts.TimeStamp, time.Local)
if err != nil {
return errors.Fatalf("error in time option: %v\n", err)
}
@@ -359,6 +395,12 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
var t tomb.Tomb
term.Print("open repository\n")
repo, err := OpenRepository(gopts)
if err != nil {
return err
}
p := ui.NewBackup(term, gopts.verbosity)
// use the terminal for stdout/stderr
@@ -380,12 +422,6 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
t.Go(func() error { return p.Run(t.Context(gopts.ctx)) })
p.V("open repository")
repo, err := OpenRepository(gopts)
if err != nil {
return err
}
p.V("lock repository")
lock, err := lockRepo(repo)
defer unlockRepo(lock)
@@ -393,7 +429,13 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
return err
}
// rejectFuncs collect functions that can reject items from the backup
// rejectByNameFuncs collect functions that can reject items from the backup based on path only
rejectByNameFuncs, err := collectRejectByNameFuncs(opts, repo, targets)
if err != nil {
return err
}
// rejectFuncs collect functions that can reject items from the backup based on path and file info
rejectFuncs, err := collectRejectFuncs(opts, repo, targets)
if err != nil {
return err
@@ -414,6 +456,15 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
p.V("using parent snapshot %v\n", parentSnapshotID.Str())
}
selectByNameFilter := func(item string) bool {
for _, reject := range rejectByNameFuncs {
if reject(item) {
return false
}
}
return true
}
selectFilter := func(item string, fi os.FileInfo) bool {
for _, reject := range rejectFuncs {
if reject(item, fi) {
@@ -436,6 +487,7 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
}
sc := archiver.NewScanner(targetFS)
sc.SelectByName = selectByNameFilter
sc.Select = selectFilter
sc.Error = p.ScannerError
sc.Result = p.ReportTotal
@@ -444,6 +496,7 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
t.Go(func() error { return sc.Scan(t.Context(gopts.ctx), targets) })
arch := archiver.New(repo, targetFS, archiver.Options{})
arch.SelectByName = selectByNameFilter
arch.Select = selectFilter
arch.WithAtime = opts.WithAtime
arch.Error = p.Error
@@ -459,7 +512,7 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
Excludes: opts.Excludes,
Tags: opts.Tags,
Time: timeStamp,
Hostname: opts.Hostname,
Hostname: opts.Host,
ParentSnapshot: *parentSnapshotID,
}

View File

@@ -2,6 +2,7 @@ package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"time"
@@ -9,6 +10,7 @@ import (
"github.com/restic/restic/internal/cache"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/ui/table"
"github.com/spf13/cobra"
)
@@ -28,6 +30,7 @@ The "cache" command allows listing and cleaning local cache directories.
type CacheOptions struct {
Cleanup bool
MaxAge uint
NoSize bool
}
var cacheOptions CacheOptions
@@ -38,6 +41,7 @@ func init() {
f := cmdCache.Flags()
f.BoolVar(&cacheOptions.Cleanup, "cleanup", false, "remove old cache directories")
f.UintVar(&cacheOptions.MaxAge, "max-age", 30, "max age in `days` for cache directories to be considered old")
f.BoolVar(&cacheOptions.NoSize, "no-size", false, "do not output the size of the cache directories")
}
func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error {
@@ -85,9 +89,22 @@ func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error {
return nil
}
tab := NewTable()
tab.Header = fmt.Sprintf("%-14s %-16s %s", "Repository ID", "Last Used", "Old")
tab.RowFormat = "%-14s %-16s %s"
tab := table.New()
type data struct {
ID string
Last string
Old string
Size string
}
tab.AddColumn("Repo ID", "{{ .ID }}")
tab.AddColumn("Last Used", "{{ .Last }}")
tab.AddColumn("Old", "{{ .Old }}")
if !opts.NoSize {
tab.AddColumn("Size", "{{ .Size }}")
}
dirs, err := cache.All(cachedir)
if err != nil {
@@ -109,14 +126,41 @@ func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error {
old = "yes"
}
tab.Rows = append(tab.Rows, []interface{}{
var size string
if !opts.NoSize {
bytes, err := dirSize(filepath.Join(cachedir, entry.Name()))
if err != nil {
return err
}
size = fmt.Sprintf("%11s", formatBytes(uint64(bytes)))
}
tab.AddRow(data{
entry.Name()[:10],
fmt.Sprintf("%d days ago", uint(time.Since(entry.ModTime()).Hours()/24)),
old,
size,
})
}
tab.Write(gopts.stdout)
Printf("%d cache dirs in %s\n", len(dirs), cachedir)
return nil
}
func dirSize(path string) (int64, error) {
var size int64
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err != nil || info == nil {
return err
}
if !info.IsDir() {
size += info.Size()
}
return nil
})
return size, err
}

View File

@@ -21,11 +21,11 @@ The "diff" command shows differences from the first to the second snapshot. The
first characters in each line display what has happened to a particular file or
directory:
+ The item was added
- The item was removed
U The metadata (access mode, timestamps, ...) for the item was updated
M The file's content was modified
T The type was changed, e.g. a file was made a symlink
* + The item was added
* - The item was removed
* U The metadata (access mode, timestamps, ...) for the item was updated
* M The file's content was modified
* T The type was changed, e.g. a file was made a symlink
`,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"github.com/restic/restic/internal/debug"
@@ -47,12 +48,12 @@ func init() {
flags.StringArrayVar(&dumpOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path` for snapshot ID \"latest\"")
}
func splitPath(path string) []string {
d, f := filepath.Split(path)
func splitPath(p string) []string {
d, f := path.Split(p)
if d == "" || d == "/" {
return []string{f}
}
s := splitPath(filepath.Clean(d))
s := splitPath(path.Clean(d))
return append(s, f)
}

View File

@@ -16,27 +16,38 @@ import (
)
var cmdFind = &cobra.Command{
Use: "find [flags] PATTERN",
Short: "Find a file or directory",
Use: "find [flags] PATTERN...",
Short: "Find a file, a directory or restic IDs",
Long: `
The "find" command searches for files or directories in snapshots stored in the
repo. `,
repo.
It can also be used to search for restic blobs or trees for troubleshooting.`,
Example: `restic find config.json
restic find --json "*.yml" "*.json"
restic find --json --blob 420f620f b46ebe8a ddd38656
restic find --show-pack-id --blob 420f620f
restic find --tree 577c2bc9 f81f2e22 a62827a9
restic find --pack 025c1d06`,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runFind(findOptions, globalOptions, args)
},
}
const shortStr = 8 // Length of short IDs: 4 bytes as hex strings
// FindOptions bundles all options for the find command.
type FindOptions struct {
Oldest string
Newest string
Snapshots []string
CaseInsensitive bool
ListLong bool
Host string
Paths []string
Tags restic.TagLists
Oldest string
Newest string
Snapshots []string
BlobID, TreeID bool
PackID, ShowPackID bool
CaseInsensitive bool
ListLong bool
Host string
Paths []string
Tags restic.TagLists
}
var findOptions FindOptions
@@ -48,6 +59,10 @@ func init() {
f.StringVarP(&findOptions.Oldest, "oldest", "O", "", "oldest modification date/time")
f.StringVarP(&findOptions.Newest, "newest", "N", "", "newest modification date/time")
f.StringArrayVarP(&findOptions.Snapshots, "snapshot", "s", nil, "snapshot `id` to search in (can be given multiple times)")
f.BoolVar(&findOptions.BlobID, "blob", false, "pattern is a blob-ID")
f.BoolVar(&findOptions.TreeID, "tree", false, "pattern is a tree-ID")
f.BoolVar(&findOptions.PackID, "pack", false, "pattern is a pack-ID")
f.BoolVar(&findOptions.ShowPackID, "show-pack-id", false, "display the pack-ID the blobs belong to (with --blob)")
f.BoolVarP(&findOptions.CaseInsensitive, "ignore-case", "i", false, "ignore case for pattern")
f.BoolVarP(&findOptions.ListLong, "long", "l", false, "use a long listing format showing size and mode")
@@ -58,7 +73,7 @@ func init() {
type findPattern struct {
oldest, newest time.Time
pattern string
pattern []string
ignoreCase bool
}
@@ -95,7 +110,7 @@ type statefulOutput struct {
hits int
}
func (s *statefulOutput) PrintJSON(path string, node *restic.Node) {
func (s *statefulOutput) PrintPatternJSON(path string, node *restic.Node) {
type findNode restic.Node
b, err := json.Marshal(struct {
// Add these attributes
@@ -139,7 +154,7 @@ func (s *statefulOutput) PrintJSON(path string, node *restic.Node) {
s.hits++
}
func (s *statefulOutput) PrintNormal(path string, node *restic.Node) {
func (s *statefulOutput) PrintPatternNormal(path string, node *restic.Node) {
if s.newsn != s.oldsn {
if s.oldsn != nil {
Verbosef("\n")
@@ -150,11 +165,62 @@ func (s *statefulOutput) PrintNormal(path string, node *restic.Node) {
Printf(formatNode(path, node, s.ListLong) + "\n")
}
func (s *statefulOutput) Print(path string, node *restic.Node) {
func (s *statefulOutput) PrintPattern(path string, node *restic.Node) {
if s.JSON {
s.PrintJSON(path, node)
s.PrintPatternJSON(path, node)
} else {
s.PrintNormal(path, node)
s.PrintPatternNormal(path, node)
}
}
func (s *statefulOutput) PrintObjectJSON(kind, id, nodepath, treeID string, sn *restic.Snapshot) {
b, err := json.Marshal(struct {
// Add these attributes
ObjectType string `json:"object_type"`
ID string `json:"id"`
Path string `json:"path"`
ParentTree string `json:"parent_tree,omitempty"`
SnapshotID string `json:"snapshot"`
Time time.Time `json:"time,omitempty"`
}{
ObjectType: kind,
ID: id,
Path: nodepath,
SnapshotID: sn.ID().String(),
ParentTree: treeID,
Time: sn.Time,
})
if err != nil {
Warnf("Marshall failed: %v\n", err)
return
}
if !s.inuse {
Printf("[")
s.inuse = true
}
if s.hits > 0 {
Printf(",")
}
Printf(string(b))
s.hits++
}
func (s *statefulOutput) PrintObjectNormal(kind, id, nodepath, treeID string, sn *restic.Snapshot) {
Printf("Found %s %s\n", kind, id)
if kind == "blob" {
Printf(" ... in file %s\n", nodepath)
Printf(" (tree %s)\n", treeID)
} else {
Printf(" ... path %s\n", nodepath)
}
Printf(" ... in snapshot %s (%s)\n", sn.ID().Str(), sn.Time.Local().Format(TimeFormat))
}
func (s *statefulOutput) PrintObject(kind, id, nodepath, treeID string, sn *restic.Snapshot) {
if s.JSON {
s.PrintObjectJSON(kind, id, nodepath, treeID, sn)
} else {
s.PrintObjectNormal(kind, id, nodepath, treeID, sn)
}
}
@@ -179,6 +245,9 @@ type Finder struct {
pat findPattern
out statefulOutput
ignoreTrees restic.IDSet
blobIDs map[string]struct{}
treeIDs map[string]struct{}
itemsFound int
}
func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error {
@@ -189,7 +258,7 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error
}
f.out.newsn = sn
return walker.Walk(ctx, f.repo, *sn.Tree, f.ignoreTrees, func(nodepath string, node *restic.Node, err error) (bool, error) {
return walker.Walk(ctx, f.repo, *sn.Tree, f.ignoreTrees, func(_ restic.ID, nodepath string, node *restic.Node, err error) (bool, error) {
if err != nil {
return false, err
}
@@ -203,9 +272,17 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error
normalizedNodepath = strings.ToLower(nodepath)
}
foundMatch, err := filter.Match(f.pat.pattern, normalizedNodepath)
if err != nil {
return false, err
var foundMatch bool
for _, pat := range f.pat.pattern {
found, err := filter.Match(pat, normalizedNodepath)
if err != nil {
return false, err
}
if found {
foundMatch = true
break
}
}
var (
@@ -213,9 +290,16 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error
errIfNoMatch error
)
if node.Type == "dir" {
childMayMatch, err := filter.ChildMatch(f.pat.pattern, normalizedNodepath)
if err != nil {
return false, err
var childMayMatch bool
for _, pat := range f.pat.pattern {
mayMatch, err := filter.ChildMatch(pat, normalizedNodepath)
if err != nil {
return false, err
}
if mayMatch {
childMayMatch = true
break
}
}
if !childMayMatch {
@@ -241,20 +325,158 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error
}
debug.Log(" found match\n")
f.out.Print(nodepath, node)
f.out.PrintPattern(nodepath, node)
return false, nil
})
}
func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error {
debug.Log("searching IDs in snapshot %s", sn.ID())
if sn.Tree == nil {
return errors.Errorf("snapshot %v has no tree", sn.ID().Str())
}
f.out.newsn = sn
return walker.Walk(ctx, f.repo, *sn.Tree, f.ignoreTrees, func(parentTreeID restic.ID, nodepath string, node *restic.Node, err error) (bool, error) {
if err != nil {
return false, err
}
if node == nil {
return false, nil
}
if node.Type == "dir" && f.treeIDs != nil {
treeID := node.Subtree
found := false
if _, ok := f.treeIDs[treeID.Str()]; ok {
found = true
} else if _, ok := f.treeIDs[treeID.String()]; ok {
found = true
}
if found {
f.out.PrintObject("tree", treeID.String(), nodepath, "", sn)
f.itemsFound++
// Terminate if we have found all trees (and we are not
// looking for blobs)
if f.itemsFound >= len(f.treeIDs) && f.blobIDs == nil {
// Return an error to terminate the Walk
return true, errors.New("OK")
}
}
}
if node.Type == "file" && f.blobIDs != nil {
for _, id := range node.Content {
idStr := id.String()
if _, ok := f.blobIDs[idStr]; !ok {
// Look for short ID form
if _, ok := f.blobIDs[idStr[:shortStr]]; !ok {
continue
}
// Replace the short ID with the long one
f.blobIDs[idStr] = struct{}{}
delete(f.blobIDs, idStr[:shortStr])
}
f.out.PrintObject("blob", idStr, nodepath, parentTreeID.String(), sn)
break
}
}
return false, nil
})
}
// packsToBlobs converts the list of pack IDs to a list of blob IDs that
// belong to those packs.
func (f *Finder) packsToBlobs(ctx context.Context, packs []string) error {
packIDs := make(map[string]struct{})
for _, p := range packs {
packIDs[p] = struct{}{}
}
if f.blobIDs == nil {
f.blobIDs = make(map[string]struct{})
}
allPacksFound := false
packsFound := 0
debug.Log("Looking for packs...")
err := f.repo.List(ctx, restic.DataFile, func(id restic.ID, size int64) error {
if allPacksFound {
return nil
}
idStr := id.String()
if _, ok := packIDs[idStr]; !ok {
// Look for short ID form
if _, ok := packIDs[idStr[:shortStr]]; !ok {
return nil
}
}
debug.Log("Found pack %s", idStr)
blobs, _, err := f.repo.ListPack(ctx, id, size)
if err != nil {
return err
}
for _, b := range blobs {
f.blobIDs[b.ID.String()] = struct{}{}
}
// Stop searching when all packs have been found
packsFound++
if packsFound >= len(packIDs) {
allPacksFound = true
}
return nil
})
if err != nil {
return err
}
if !allPacksFound {
return errors.Fatal("unable to find all specified pack(s)")
}
debug.Log("%d blobs found", len(f.blobIDs))
return nil
}
func (f *Finder) findBlobsPacks(ctx context.Context) {
idx := f.repo.Index()
for i := range f.blobIDs {
rid, err := restic.ParseID(i)
if err != nil {
Printf("Note: cannot find pack for blob '%s', unable to parse ID: %v\n", i, err)
continue
}
blobs, found := idx.Lookup(rid, restic.DataBlob)
if !found {
Printf("Blob %s not found in the index\n", rid.Str())
continue
}
for _, b := range blobs {
if b.ID.Equal(rid) {
Printf("Blob belongs to pack %s\n ... Pack %s: %s\n", b.PackID, b.PackID.Str(), b.String())
break
}
}
}
}
func runFind(opts FindOptions, gopts GlobalOptions, args []string) error {
if len(args) != 1 {
if len(args) == 0 {
return errors.Fatal("wrong number of arguments")
}
var err error
pat := findPattern{pattern: args[0]}
pat := findPattern{pattern: args}
if opts.CaseInsensitive {
pat.pattern = strings.ToLower(pat.pattern)
for i := range pat.pattern {
pat.pattern[i] = strings.ToLower(pat.pattern[i])
}
pat.ignoreCase = true
}
@@ -270,6 +492,14 @@ func runFind(opts FindOptions, gopts GlobalOptions, args []string) error {
}
}
// Check at most only one kind of IDs is provided: currently we
// can't mix types
if (opts.BlobID && opts.TreeID) ||
(opts.BlobID && opts.PackID) ||
(opts.TreeID && opts.PackID) {
return errors.Fatal("cannot have several ID types")
}
repo, err := OpenRepository(gopts)
if err != nil {
return err
@@ -296,12 +526,40 @@ func runFind(opts FindOptions, gopts GlobalOptions, args []string) error {
out: statefulOutput{ListLong: opts.ListLong, JSON: globalOptions.JSON},
ignoreTrees: restic.NewIDSet(),
}
if opts.BlobID {
f.blobIDs = make(map[string]struct{})
for _, pat := range f.pat.pattern {
f.blobIDs[pat] = struct{}{}
}
}
if opts.TreeID {
f.treeIDs = make(map[string]struct{})
for _, pat := range f.pat.pattern {
f.treeIDs[pat] = struct{}{}
}
}
if opts.PackID {
f.packsToBlobs(ctx, []string{f.pat.pattern[0]}) // TODO: support multiple packs
}
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, opts.Snapshots) {
if f.blobIDs != nil || f.treeIDs != nil {
if err = f.findIDs(ctx, sn); err != nil && err.Error() != "OK" {
return err
}
continue
}
if err = f.findInSnapshot(ctx, sn); err != nil {
return err
}
}
f.out.Finish()
if opts.ShowPackID && f.blobIDs != nil {
f.findBlobsPacks(ctx)
}
return nil
}

View File

@@ -59,14 +59,15 @@ func init() {
f.IntVarP(&forgetOptions.Weekly, "keep-weekly", "w", 0, "keep the last `n` weekly snapshots")
f.IntVarP(&forgetOptions.Monthly, "keep-monthly", "m", 0, "keep the last `n` monthly snapshots")
f.IntVarP(&forgetOptions.Yearly, "keep-yearly", "y", 0, "keep the last `n` yearly snapshots")
f.VarP(&forgetOptions.Within, "keep-within", "", "keep snapshots that were created within `duration` before the newest (e.g. 1y5m7d)")
f.VarP(&forgetOptions.Within, "keep-within", "", "keep snapshots that are newer than `duration` (eg. 1y5m7d2h) relative to the latest snapshot")
f.Var(&forgetOptions.KeepTags, "keep-tag", "keep snapshots with this `taglist` (can be specified multiple times)")
// Sadly the commonly used shortcut `H` is already used.
f.StringVar(&forgetOptions.Host, "host", "", "only consider snapshots with the given `host`")
// Deprecated since 2017-03-07.
f.StringVar(&forgetOptions.Host, "hostname", "", "only consider snapshots with the given `hostname` (deprecated)")
f.StringVar(&forgetOptions.Host, "hostname", "", "only consider snapshots with the given `hostname`")
f.MarkDeprecated("hostname", "use --host")
f.Var(&forgetOptions.Tags, "tag", "only consider snapshots which include this `taglist` in the format `tag[,tag,...]` (can be specified multiple times)")
f.StringArrayVar(&forgetOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path` (can be specified multiple times)")
f.BoolVarP(&forgetOptions.Compact, "compact", "c", false, "use compact format")
@@ -206,17 +207,17 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
}
Verbosef(":\n\n")
keep, remove := restic.ApplyPolicy(snapshotGroup, policy)
keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy)
if len(keep) != 0 && !gopts.Quiet {
Printf("keep %d snapshots:\n", len(keep))
PrintSnapshots(globalOptions.stdout, keep, opts.Compact)
PrintSnapshots(globalOptions.stdout, keep, reasons, opts.Compact)
Printf("\n")
}
if len(remove) != 0 && !gopts.Quiet {
Printf("remove %d snapshots:\n", len(remove))
PrintSnapshots(globalOptions.stdout, remove, opts.Compact)
PrintSnapshots(globalOptions.stdout, remove, nil, opts.Compact)
Printf("\n")
}

View File

@@ -3,7 +3,6 @@ package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strings"
@@ -11,6 +10,7 @@ import (
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui/table"
"github.com/spf13/cobra"
)
@@ -36,53 +36,18 @@ func init() {
flags.StringVarP(&newPasswordFile, "new-password-file", "", "", "the file from which to load a new password")
}
type keyInfo struct {
Current bool `json:"current"`
ID string `json:"id"`
UserName string `json:"userName"`
HostName string `json:"hostName"`
Created string `json:"created"`
}
func (ki keyInfo) CurrentStr() string {
if ki.Current {
return "*"
}
return " "
}
func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions) error {
var (
appendKey func(keyInfo)
printKeys func() error
)
switch gopts.JSON {
case true:
var keys []keyInfo
appendKey = func(key keyInfo) {
keys = append(keys, key)
}
printKeys = func() error {
return json.NewEncoder(gopts.stdout).Encode(keys)
}
default:
tab := NewTable()
tab.Header = fmt.Sprintf(" %-10s %-10s %-10s %s", "ID", "User", "Host", "Created")
tab.RowFormat = "%s%-10s %-10s %-10s %s"
appendKey = func(key keyInfo) {
tab.Rows = append(tab.Rows, []interface{}{key.CurrentStr(), key.ID, key.UserName, key.HostName, key.Created})
}
printKeys = func() error {
return tab.Write(globalOptions.stdout)
}
type keyInfo struct {
Current bool `json:"current"`
ID string `json:"id"`
UserName string `json:"userName"`
HostName string `json:"hostName"`
Created string `json:"created"`
}
if err := s.List(ctx, restic.KeyFile, func(id restic.ID, size int64) error {
var keys []keyInfo
err := s.List(ctx, restic.KeyFile, func(id restic.ID, size int64) error {
k, err := repository.LoadKey(ctx, s, id.String())
if err != nil {
Warnf("LoadKey() failed: %v\n", err)
@@ -94,17 +59,32 @@ func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions
ID: id.Str(),
UserName: k.Username,
HostName: k.Hostname,
Created: k.Created.Format(TimeFormat),
Created: k.Created.Local().Format(TimeFormat),
}
appendKey(key)
keys = append(keys, key)
return nil
}); err != nil {
})
if err != nil {
return err
}
return printKeys()
if gopts.JSON {
return json.NewEncoder(globalOptions.stdout).Encode(keys)
}
tab := table.New()
tab.AddColumn(" ID", "{{if .Current}}*{{else}} {{end}}{{ .ID }}")
tab.AddColumn("User", "{{ .UserName }}")
tab.AddColumn("Host", "{{ .HostName }}")
tab.AddColumn("Created", "{{ .Created }}")
for _, key := range keys {
tab.AddRow(key)
}
return tab.Write(globalOptions.stdout)
}
// testKeyNewPassword is used to set a new password during integration testing.

View File

@@ -2,21 +2,37 @@ package main
import (
"context"
"encoding/json"
"os"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/walker"
)
var cmdLs = &cobra.Command{
Use: "ls [flags] [snapshot-ID ...]",
Use: "ls [flags] [snapshotID] [dir...]",
Short: "List files in a snapshot",
Long: `
The "ls" command allows listing files and directories in a snapshot.
The "ls" command lists files and directories in a snapshot.
The special snapshot-ID "latest" can be used to list files and directories of the latest snapshot in the repository.
The special snapshot ID "latest" can be used to list files and
directories of the latest snapshot in the repository. The
--host flag can be used in conjunction to select the latest
snapshot originating from a certain host only.
File listings can optionally be filtered by directories. Any
positional arguments after the snapshot ID are interpreted as
absolute directory paths, and only files inside those directories
will be listed. If the --recursive flag is used, then the filter
will allow traversing into matching directories' subfolders.
Any directory paths specified must be absolute (starting with
a path separator); paths use the forward slash '/' as separator.
`,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -26,10 +42,11 @@ The special snapshot-ID "latest" can be used to list files and directories of th
// LsOptions collects all options for the ls command.
type LsOptions struct {
ListLong bool
Host string
Tags restic.TagLists
Paths []string
ListLong bool
Host string
Tags restic.TagLists
Paths []string
Recursive bool
}
var lsOptions LsOptions
@@ -39,10 +56,31 @@ func init() {
flags := cmdLs.Flags()
flags.BoolVarP(&lsOptions.ListLong, "long", "l", false, "use a long listing format showing size and mode")
flags.StringVarP(&lsOptions.Host, "host", "H", "", "only consider snapshots for this `host`, when no snapshot ID is given")
flags.Var(&lsOptions.Tags, "tag", "only consider snapshots which include this `taglist`, when no snapshot ID is given")
flags.StringArrayVar(&lsOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`, when no snapshot ID is given")
flags.BoolVar(&lsOptions.Recursive, "recursive", false, "include files in subfolders of the listed directories")
}
type lsSnapshot struct {
*restic.Snapshot
ID *restic.ID `json:"id"`
ShortID string `json:"short_id"`
StructType string `json:"struct_type"` // "snapshot"
}
type lsNode struct {
Name string `json:"name"`
Type string `json:"type"`
Path string `json:"path"`
UID uint32 `json:"uid"`
GID uint32 `json:"gid"`
Size uint64 `json:"size,omitempty"`
Mode os.FileMode `json:"mode,omitempty"`
ModTime time.Time `json:"mtime,omitempty"`
AccessTime time.Time `json:"atime,omitempty"`
ChangeTime time.Time `json:"ctime,omitempty"`
StructType string `json:"struct_type"` // "node"
}
func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
@@ -50,6 +88,51 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
return errors.Fatal("Invalid arguments, either give one or more snapshot IDs or set filters.")
}
// extract any specific directories to walk
var dirs []string
if len(args) > 1 {
dirs = args[1:]
for _, dir := range dirs {
if !strings.HasPrefix(dir, "/") {
return errors.Fatal("All path filters must be absolute, starting with a forward slash '/'")
}
}
}
withinDir := func(nodepath string) bool {
if len(dirs) == 0 {
return true
}
for _, dir := range dirs {
// we're within one of the selected dirs, example:
// nodepath: "/test/foo"
// dir: "/test"
if fs.HasPathPrefix(dir, nodepath) {
return true
}
}
return false
}
approachingMatchingTree := func(nodepath string) bool {
if len(dirs) == 0 {
return true
}
for _, dir := range dirs {
// the current node path is a prefix for one of the
// directories, so we're interested in something deeper in the
// tree. Example:
// nodepath: "/test"
// dir: "/test/foo"
if fs.HasPathPrefix(nodepath, dir) {
return true
}
}
return false
}
repo, err := OpenRepository(gopts)
if err != nil {
return err
@@ -61,23 +144,88 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
ctx, cancel := context.WithCancel(gopts.ctx)
defer cancel()
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args) {
Verbosef("snapshot %s of %v at %s):\n", sn.ID().Str(), sn.Paths, sn.Time)
err := walker.Walk(ctx, repo, *sn.Tree, nil, func(nodepath string, node *restic.Node, err error) (bool, error) {
var (
printSnapshot func(sn *restic.Snapshot)
printNode func(path string, node *restic.Node)
)
if gopts.JSON {
enc := json.NewEncoder(gopts.stdout)
printSnapshot = func(sn *restic.Snapshot) {
enc.Encode(lsSnapshot{
Snapshot: sn,
ID: sn.ID(),
ShortID: sn.ID().Str(),
StructType: "snapshot",
})
}
printNode = func(path string, node *restic.Node) {
enc.Encode(lsNode{
Name: node.Name,
Type: node.Type,
Path: path,
UID: node.UID,
GID: node.GID,
Size: node.Size,
Mode: node.Mode,
ModTime: node.ModTime,
AccessTime: node.AccessTime,
ChangeTime: node.ChangeTime,
StructType: "node",
})
}
} else {
printSnapshot = func(sn *restic.Snapshot) {
Verbosef("snapshot %s of %v filtered by %v at %s):\n", sn.ID().Str(), sn.Paths, dirs, sn.Time)
}
printNode = func(path string, node *restic.Node) {
Printf("%s\n", formatNode(path, node, lsOptions.ListLong))
}
}
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args[:1]) {
printSnapshot(sn)
err := walker.Walk(ctx, repo, *sn.Tree, nil, func(_ restic.ID, nodepath string, node *restic.Node, err error) (bool, error) {
if err != nil {
return false, err
}
if node == nil {
return false, nil
}
Printf("%s\n", formatNode(nodepath, node, lsOptions.ListLong))
if withinDir(nodepath) {
// if we're within a dir, print the node
printNode(nodepath, node)
// if recursive listing is requested, signal the walker that it
// should continue walking recursively
if opts.Recursive {
return false, nil
}
}
// if there's an upcoming match deeper in the tree (but we're not
// there yet), signal the walker to descend into any subdirs
if approachingMatchingTree(nodepath) {
return false, nil
}
// otherwise, signal the walker to not walk recursively into any
// subdirs
if node.Type == "dir" {
return false, walker.SkipNode
}
return false, nil
})
if err != nil {
return err
}
}
return nil
}

View File

@@ -53,13 +53,14 @@ For details please see the documentation for time.Format() at:
// MountOptions collects all options for the mount command.
type MountOptions struct {
OwnerRoot bool
AllowRoot bool
AllowOther bool
Host string
Tags restic.TagLists
Paths []string
SnapshotTemplate string
OwnerRoot bool
AllowRoot bool
AllowOther bool
NoDefaultPermissions bool
Host string
Tags restic.TagLists
Paths []string
SnapshotTemplate string
}
var mountOptions MountOptions
@@ -71,6 +72,7 @@ func init() {
mountFlags.BoolVar(&mountOptions.OwnerRoot, "owner-root", false, "use 'root' as the owner of files and dirs")
mountFlags.BoolVar(&mountOptions.AllowRoot, "allow-root", false, "allow root user to access the data in the mounted directory")
mountFlags.BoolVar(&mountOptions.AllowOther, "allow-other", false, "allow other users to access the data in the mounted directory")
mountFlags.BoolVar(&mountOptions.NoDefaultPermissions, "no-default-permissions", false, "for 'allow-other', ignore Unix permissions and allow users to read all snapshot files")
mountFlags.StringVarP(&mountOptions.Host, "host", "H", "", `only consider snapshots for this host`)
mountFlags.Var(&mountOptions.Tags, "tag", "only consider snapshots which include this `taglist`")
@@ -118,6 +120,11 @@ func mount(opts MountOptions, gopts GlobalOptions, mountpoint string) error {
if opts.AllowOther {
mountOptions = append(mountOptions, systemFuse.AllowOther())
// let the kernel check permissions unless it is explicitly disabled
if !opts.NoDefaultPermissions {
mountOptions = append(mountOptions, systemFuse.DefaultPermissions())
}
}
c, err := systemFuse.Mount(mountpoint, mountOptions...)

View File

@@ -149,8 +149,8 @@ func pruneRepository(gopts GlobalOptions, repo restic.Repository) error {
len(idx.Packs), blobs, formatBytes(uint64(stats.bytes)))
blobCount := make(map[restic.BlobHandle]int)
duplicateBlobs := 0
duplicateBytes := 0
var duplicateBlobs uint64
var duplicateBytes uint64
// find duplicate blobs
for _, p := range idx.Packs {
@@ -161,7 +161,7 @@ func pruneRepository(gopts GlobalOptions, repo restic.Repository) error {
if blobCount[h] > 1 {
duplicateBlobs++
duplicateBytes += int(entry.Length)
duplicateBytes += uint64(entry.Length)
}
}
}
@@ -252,7 +252,7 @@ func pruneRepository(gopts GlobalOptions, repo restic.Repository) error {
continue
}
removeBytes += int(blob.Length)
removeBytes += uint64(blob.Length)
}
if hasActiveBlob {

148
cmd/restic/cmd_recover.go Normal file
View File

@@ -0,0 +1,148 @@
package main
import (
"os"
"time"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/spf13/cobra"
)
var cmdRecover = &cobra.Command{
Use: "recover [flags]",
Short: "Recover data from the repository",
Long: `
The "recover" command build a new snapshot from all directories it can find in
the raw data of the repository. It can be used if, for example, a snapshot has
been removed by accident with "forget".
`,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runRecover(globalOptions)
},
}
func init() {
cmdRoot.AddCommand(cmdRecover)
}
func runRecover(gopts GlobalOptions) error {
hostname, err := os.Hostname()
if err != nil {
return err
}
repo, err := OpenRepository(gopts)
if err != nil {
return err
}
lock, err := lockRepo(repo)
defer unlockRepo(lock)
if err != nil {
return err
}
Verbosef("load index files\n")
if err = repo.LoadIndex(gopts.ctx); err != nil {
return err
}
// trees maps a tree ID to whether or not it is referenced by a different
// tree. If it is not referenced, we have a root tree.
trees := make(map[restic.ID]bool)
for blob := range repo.Index().Each(gopts.ctx) {
if blob.Blob.Type != restic.TreeBlob {
continue
}
trees[blob.Blob.ID] = false
}
cur := 0
max := len(trees)
Verbosef("load %d trees\n\n", len(trees))
for id := range trees {
cur++
Verbosef("\rtree (%v/%v)", cur, max)
if !trees[id] {
trees[id] = false
}
tree, err := repo.LoadTree(gopts.ctx, id)
if err != nil {
Warnf("unable to load tree %v: %v\n", id.Str(), err)
continue
}
for _, node := range tree.Nodes {
if node.Type != "dir" || node.Subtree == nil {
continue
}
subtree := *node.Subtree
trees[subtree] = true
}
}
Verbosef("\ndone\n")
roots := restic.NewIDSet()
for id, seen := range trees {
if seen {
continue
}
roots.Insert(id)
}
Verbosef("found %d roots\n", len(roots))
tree := restic.NewTree()
for id := range roots {
var subtreeID = id
node := restic.Node{
Type: "dir",
Name: id.Str(),
Mode: 0755,
Subtree: &subtreeID,
AccessTime: time.Now(),
ModTime: time.Now(),
ChangeTime: time.Now(),
}
tree.Insert(&node)
}
treeID, err := repo.SaveTree(gopts.ctx, tree)
if err != nil {
return errors.Fatalf("unable to save new tree to the repo: %v", err)
}
err = repo.Flush(gopts.ctx)
if err != nil {
return errors.Fatalf("unable to save blobs to the repo: %v", err)
}
err = repo.SaveIndex(gopts.ctx)
if err != nil {
return errors.Fatalf("unable to save new index to the repo: %v", err)
}
sn, err := restic.NewSnapshot([]string{"/recover"}, []string{}, hostname, time.Now())
if err != nil {
return errors.Fatalf("unable to save snapshot: %v", err)
}
sn.Tree = &treeID
id, err := repo.SaveJSONUnpacked(gopts.ctx, restic.SnapshotFile, sn)
if err != nil {
return errors.Fatalf("unable to save snapshot: %v", err)
}
Printf("saved new snapshot %v\n", id.Str())
return nil
}

View File

@@ -113,8 +113,8 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error {
}
totalErrors := 0
res.Error = func(dir string, node *restic.Node, err error) error {
Warnf("ignoring error for %s: %s\n", dir, err)
res.Error = func(location string, err error) error {
Warnf("ignoring error for %s: %s\n", location, err)
totalErrors++
return nil
}

View File

@@ -0,0 +1,73 @@
// xbuild selfupdate
package main
import (
"os"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/selfupdate"
"github.com/spf13/cobra"
)
var cmdSelfUpdate = &cobra.Command{
Use: "self-update [flags]",
Short: "Update the restic binary",
Long: `
The command "self-update" downloads the latest stable release of restic from
GitHub and replaces the currently running binary. After download, the
authenticity of the binary is verified using the GPG signature on the release
files.
`,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runSelfUpdate(selfUpdateOptions, globalOptions, args)
},
}
// SelfUpdateOptions collects all options for the update-restic command.
type SelfUpdateOptions struct {
Output string
}
var selfUpdateOptions SelfUpdateOptions
func init() {
cmdRoot.AddCommand(cmdSelfUpdate)
flags := cmdSelfUpdate.Flags()
flags.StringVar(&selfUpdateOptions.Output, "output", "", "Save the downloaded file as `filename` (default: running binary itself)")
}
func runSelfUpdate(opts SelfUpdateOptions, gopts GlobalOptions, args []string) error {
if opts.Output == "" {
file, err := os.Executable()
if err != nil {
return errors.Wrap(err, "unable to find executable")
}
opts.Output = file
}
fi, err := os.Lstat(opts.Output)
if err != nil {
return err
}
if !fi.Mode().IsRegular() {
return errors.Errorf("output file %v is not a normal file, use --output to specify a different file", opts.Output)
}
Printf("writing restic to %v\n", opts.Output)
v, err := selfupdate.DownloadLatestStableRelease(gopts.ctx, opts.Output, version, Verbosef)
if err != nil {
return errors.Fatalf("unable to update restic: %v", err)
}
if v != version {
Printf("successfully updated restic to version %v\n", v)
}
return nil
}

View File

@@ -9,6 +9,7 @@ import (
"strings"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui/table"
"github.com/spf13/cobra"
)
@@ -81,7 +82,7 @@ func runSnapshots(opts SnapshotOptions, gopts GlobalOptions, args []string) erro
}
return nil
}
PrintSnapshots(gopts.stdout, list, opts.Compact)
PrintSnapshots(gopts.stdout, list, nil, opts.Compact)
return nil
}
@@ -123,7 +124,16 @@ func FilterLastSnapshots(list restic.Snapshots) restic.Snapshots {
}
// PrintSnapshots prints a text table of the snapshots in list to stdout.
func PrintSnapshots(stdout io.Writer, list restic.Snapshots, compact bool) {
func PrintSnapshots(stdout io.Writer, list restic.Snapshots, reasons []restic.KeepReason, compact bool) {
// keep the reasons a snasphot is being kept in a map, so that it doesn't
// get lost when the list of snapshots is sorted
keepReasons := make(map[restic.ID]restic.KeepReason, len(reasons))
if len(reasons) > 0 {
for i, sn := range list {
id := sn.ID()
keepReasons[*id] = reasons[i]
}
}
// always sort the snapshots so that the newer ones are listed last
sort.SliceStable(list, func(i, j int) bool {
@@ -143,71 +153,72 @@ func PrintSnapshots(stdout io.Writer, list restic.Snapshots, compact bool) {
}
}
tab := NewTable()
if !compact {
tab.Header = fmt.Sprintf("%-8s %-19s %-*s %-*s %-3s %s", "ID", "Date", -maxHost, "Host", -maxTag, "Tags", "", "Directory")
tab.RowFormat = fmt.Sprintf("%%-8s %%-19s %%%ds %%%ds %%-3s %%s", -maxHost, -maxTag)
tab := table.New()
if compact {
tab.AddColumn("ID", "{{ .ID }}")
tab.AddColumn("Time", "{{ .Timestamp }}")
tab.AddColumn("Host", "{{ .Hostname }}")
tab.AddColumn("Tags ", `{{ join .Tags "\n" }}`)
} else {
tab.Header = fmt.Sprintf("%-8s %-19s %-*s %-*s", "ID", "Date", -maxHost, "Host", -maxTag, "Tags")
tab.RowFormat = fmt.Sprintf("%%-8s %%-19s %%%ds %%s", -maxHost)
tab.AddColumn("ID", "{{ .ID }}")
tab.AddColumn("Time", "{{ .Timestamp }}")
tab.AddColumn("Host ", "{{ .Hostname }}")
tab.AddColumn("Tags ", `{{ join .Tags "," }}`)
if len(reasons) > 0 {
tab.AddColumn("Reasons", `{{ join .Reasons "\n" }}`)
}
tab.AddColumn("Paths", `{{ join .Paths "\n" }}`)
}
type snapshot struct {
ID string
Timestamp string
Hostname string
Tags []string
Reasons []string
Paths []string
}
var multiline bool
for _, sn := range list {
if len(sn.Paths) == 0 {
continue
data := snapshot{
ID: sn.ID().Str(),
Timestamp: sn.Time.Local().Format(TimeFormat),
Hostname: sn.Hostname,
Tags: sn.Tags,
Paths: sn.Paths,
}
firstTag := ""
if len(sn.Tags) > 0 {
firstTag = sn.Tags[0]
if len(reasons) > 0 {
id := sn.ID()
data.Reasons = keepReasons[*id].Matches
}
rows := len(sn.Paths)
if rows < len(sn.Tags) {
rows = len(sn.Tags)
if len(sn.Paths) > 1 && !compact {
multiline = true
}
treeElement := " "
if rows != 1 {
treeElement = "┌──"
}
if !compact {
tab.Rows = append(tab.Rows, []interface{}{sn.ID().Str(), sn.Time.Format(TimeFormat), sn.Hostname, firstTag, treeElement, sn.Paths[0]})
} else {
allTags := ""
for _, tag := range sn.Tags {
allTags += tag + " "
}
tab.Rows = append(tab.Rows, []interface{}{sn.ID().Str(), sn.Time.Format(TimeFormat), sn.Hostname, allTags})
continue
}
if len(sn.Tags) > rows {
rows = len(sn.Tags)
}
for i := 1; i < rows; i++ {
path := ""
if len(sn.Paths) > i {
path = sn.Paths[i]
}
tag := ""
if len(sn.Tags) > i {
tag = sn.Tags[i]
}
treeElement := "│"
if i == (rows - 1) {
treeElement = "└──"
}
tab.Rows = append(tab.Rows, []interface{}{"", "", "", tag, treeElement, path})
}
tab.AddRow(data)
}
tab.Footer = fmt.Sprintf("%d snapshots", len(list))
tab.AddFooter(fmt.Sprintf("%d snapshots", len(list)))
if multiline {
// print an additional blank line between snapshots
var last int
tab.PrintData = func(w io.Writer, idx int, s string) error {
var err error
if idx == last {
_, err = fmt.Fprintf(w, "%s\n", s)
} else {
_, err = fmt.Fprintf(w, "\n%s\n", s)
}
last = idx
return err
}
}
tab.Write(stdout)
}

View File

@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/walker"
"github.com/spf13/cobra"
@@ -29,17 +30,13 @@ to calculate.
The modes are:
restore-size: (default) Counts the size of the restored files.
files-by-contents: Counts total size of files, where a file is
considered unique if it has unique contents.
raw-data: Counts the size of blobs in the repository, regardless
of how many files reference them.
blobs-per-file: A combination of files-by-contents and raw-data.
Refer to the online manual for more details about each mode.
* restore-size: (default) Counts the size of the restored files.
* files-by-contents: Counts total size of files, where a file is
considered unique if it has unique contents.
* raw-data: Counts the size of blobs in the repository, regardless of
how many files reference them.
* blobs-per-file: A combination of files-by-contents and raw-data.
* Refer to the online manual for more details about each mode.
`,
DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -51,7 +48,7 @@ func init() {
cmdRoot.AddCommand(cmdStats)
f := cmdStats.Flags()
f.StringVar(&countMode, "mode", countModeRestoreSize, "counting mode: restore-size (default), files-by-contents, blobs-per-file, or raw-data")
f.StringVar(&snapshotByHost, "host", "", "filter latest snapshot by this hostname")
f.StringVarP(&snapshotByHost, "host", "H", "", "filter latest snapshot by this hostname")
}
func runStats(gopts GlobalOptions, args []string) error {
@@ -80,6 +77,10 @@ func runStats(gopts GlobalOptions, args []string) error {
}
}
if !gopts.JSON {
Printf("scanning...\n")
}
// create a container for the stats (and other needed state)
stats := &statsContainer{
uniqueFiles: make(map[fileID]struct{}),
@@ -95,18 +96,18 @@ func runStats(gopts GlobalOptions, args []string) error {
if snapshotIDString == "latest" {
sID, err = restic.FindLatestSnapshot(ctx, repo, []string{}, []restic.TagList{}, snapshotByHost)
if err != nil {
Exitf(1, "latest snapshot for criteria not found: %v", err)
return errors.Fatalf("latest snapshot for criteria not found: %v", err)
}
} else {
sID, err = restic.FindSnapshot(repo, snapshotIDString)
if err != nil {
return err
return errors.Fatalf("error loading snapshot: %v", err)
}
}
snapshot, err := restic.LoadSnapshot(ctx, repo, sID)
if err != nil {
return err
return errors.Fatalf("error loading snapshot from repo: %v", err)
}
err = statsWalkSnapshot(ctx, snapshot, repo, stats)
@@ -144,6 +145,15 @@ func runStats(gopts GlobalOptions, args []string) error {
return nil
}
// inform the user what was scanned and how it was scanned
snapshotsScanned := snapshotIDString
if snapshotsScanned == "latest" {
snapshotsScanned = "the latest snapshot"
} else if snapshotsScanned == "" {
snapshotsScanned = "all snapshots"
}
Printf("Stats for %s in %s mode:\n", snapshotsScanned, countMode)
if stats.TotalBlobCount > 0 {
Printf(" Total Blob Count: %d\n", stats.TotalBlobCount)
}
@@ -174,7 +184,7 @@ func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo rest
}
func statsWalkTree(repo restic.Repository, stats *statsContainer) walker.WalkFunc {
return func(npath string, node *restic.Node, nodeErr error) (bool, error) {
return func(_ restic.ID, npath string, node *restic.Node, nodeErr error) (bool, error) {
if nodeErr != nil {
return true, nodeErr
}
@@ -286,7 +296,7 @@ type statsContainer struct {
// blobs that have been seen as a part of the file
fileBlobs map[string]restic.IDSet
// blobs and blobsSeen are used to count indiviudal
// blobs and blobsSeen are used to count individual
// unique blobs, independent of references to files
blobs, blobsSeen restic.BlobSet
}

View File

@@ -60,15 +60,20 @@ func (rc *rejectionCache) Store(dir string, rejected bool) {
rc.m[dir] = rejected
}
// RejectByNameFunc is a function that takes a filename of a
// file that would be included in the backup. The function returns true if it
// should be excluded (rejected) from the backup.
type RejectByNameFunc func(path string) bool
// RejectFunc is a function that takes a filename and os.FileInfo of a
// file that would be included in the backup. The function returns true if it
// should be excluded (rejected) from the backup.
type RejectFunc func(path string, fi os.FileInfo) bool
// rejectByPattern returns a RejectFunc which rejects files that match
// rejectByPattern returns a RejectByNameFunc which rejects files that match
// one of the patterns.
func rejectByPattern(patterns []string) RejectFunc {
return func(item string, fi os.FileInfo) bool {
func rejectByPattern(patterns []string) RejectByNameFunc {
return func(item string) bool {
matched, _, err := filter.List(patterns, item)
if err != nil {
Warnf("error for exclude pattern: %v", err)
@@ -83,14 +88,14 @@ func rejectByPattern(patterns []string) RejectFunc {
}
}
// rejectIfPresent returns a RejectFunc which itself returns whether a path
// should be excluded. The RejectFunc considers a file to be excluded when
// rejectIfPresent returns a RejectByNameFunc which itself returns whether a path
// should be excluded. The RejectByNameFunc considers a file to be excluded when
// it resides in a directory with an exclusion file, that is specified by
// excludeFileSpec in the form "filename[:content]". The returned error is
// non-nil if the filename component of excludeFileSpec is empty. If rc is
// non-nil, it is going to be used in the RejectFunc to expedite the evaluation
// non-nil, it is going to be used in the RejectByNameFunc to expedite the evaluation
// of a directory based on previous visits.
func rejectIfPresent(excludeFileSpec string) (RejectFunc, error) {
func rejectIfPresent(excludeFileSpec string) (RejectByNameFunc, error) {
if excludeFileSpec == "" {
return nil, errors.New("name for exclusion tagfile is empty")
}
@@ -107,7 +112,7 @@ func rejectIfPresent(excludeFileSpec string) (RejectFunc, error) {
}
debug.Log("using %q as exclusion tagfile", tf)
rc := &rejectionCache{}
fn := func(filename string, _ os.FileInfo) bool {
fn := func(filename string) bool {
return isExcludedByFile(filename, tf, tc, rc)
}
return fn, nil
@@ -252,11 +257,11 @@ func rejectByDevice(samples []string) (RejectFunc, error) {
}, nil
}
// rejectResticCache returns a RejectFunc that rejects the restic cache
// rejectResticCache returns a RejectByNameFunc that rejects the restic cache
// directory (if set).
func rejectResticCache(repo *repository.Repository) (RejectFunc, error) {
func rejectResticCache(repo *repository.Repository) (RejectByNameFunc, error) {
if repo.Cache == nil {
return func(string, os.FileInfo) bool {
return func(string) bool {
return false
}, nil
}
@@ -266,7 +271,7 @@ func rejectResticCache(repo *repository.Repository) (RejectFunc, error) {
return nil, errors.New("cacheBase is empty string")
}
return func(item string, _ os.FileInfo) bool {
return func(item string) bool {
if fs.HasPathPrefix(cacheBase, item) {
debug.Log("rejecting restic cache directory %v", item)
return true

View File

@@ -27,7 +27,7 @@ func TestRejectByPattern(t *testing.T) {
for _, tc := range tests {
t.Run("", func(t *testing.T) {
reject := rejectByPattern(patterns)
res := reject(tc.filename, nil)
res := reject(tc.filename)
if res != tc.reject {
t.Fatalf("wrong result for filename %v: want %v, got %v",
tc.filename, tc.reject, res)
@@ -140,8 +140,8 @@ func TestMultipleIsExcludedByFile(t *testing.T) {
if err != nil {
return err
}
excludedByFoo := fooExclude(p, fi)
excludedByBar := barExclude(p, fi)
excludedByFoo := fooExclude(p)
excludedByBar := barExclude(p)
excluded := excludedByFoo || excludedByBar
// the log message helps debugging in case the test fails
t.Logf("%q: %v || %v = %v", p, excludedByFoo, excludedByBar, excluded)

View File

@@ -21,7 +21,7 @@ func formatBytes(c uint64) string {
case c > 1<<10:
return fmt.Sprintf("%.3f KiB", b/(1<<10))
default:
return fmt.Sprintf("%dB", c)
return fmt.Sprintf("%d B", c)
}
}
@@ -90,6 +90,6 @@ func formatNode(path string, n *restic.Node, long bool) string {
return fmt.Sprintf("%s %5d %5d %6d %s %s%s",
mode|n.Mode, n.UID, n.GID, n.Size,
n.ModTime.Format(TimeFormat), path,
n.ModTime.Local().Format(TimeFormat), path,
target)
}

View File

@@ -34,23 +34,29 @@ import (
"github.com/restic/restic/internal/errors"
"golang.org/x/crypto/ssh/terminal"
"os/exec"
)
var version = "compiled manually"
var version = "0.9.4"
// TimeFormat is the format used for all timestamps printed by restic.
const TimeFormat = "2006-01-02 15:04:05"
// GlobalOptions hold all global options for restic.
type GlobalOptions struct {
Repo string
PasswordFile string
Quiet bool
Verbose int
NoLock bool
JSON bool
CacheDir string
NoCache bool
CACerts []string
TLSClientCert string
CleanupCache bool
Repo string
PasswordFile string
PasswordCommand string
KeyHint string
Quiet bool
Verbose int
NoLock bool
JSON bool
CacheDir string
NoCache bool
CACerts []string
TLSClientCert string
CleanupCache bool
LimitUploadKb int
LimitDownloadKb int
@@ -64,7 +70,7 @@ type GlobalOptions struct {
// 0 means: don't print any messages except errors, this is used when --quiet is specified
// 1 is the default: print essential messages
// 2 means: print more messages, report minor things, this is used when --verbose is specified
// 3 means: print very detailed debug messages, this is used when --debug is specified
// 3 means: print very detailed debug messages, this is used when --verbose 2 is specified
verbosity uint
Options []string
@@ -88,11 +94,13 @@ func init() {
f := cmdRoot.PersistentFlags()
f.StringVarP(&globalOptions.Repo, "repo", "r", os.Getenv("RESTIC_REPOSITORY"), "repository to backup to or restore from (default: $RESTIC_REPOSITORY)")
f.StringVarP(&globalOptions.PasswordFile, "password-file", "p", os.Getenv("RESTIC_PASSWORD_FILE"), "read the repository password from a file (default: $RESTIC_PASSWORD_FILE)")
f.StringVarP(&globalOptions.KeyHint, "key-hint", "", os.Getenv("RESTIC_KEY_HINT"), "key ID of key to try decrypting first (default: $RESTIC_KEY_HINT)")
f.StringVarP(&globalOptions.PasswordCommand, "password-command", "", os.Getenv("RESTIC_PASSWORD_COMMAND"), "specify a shell command to obtain a password (default: $RESTIC_PASSWORD_COMMAND)")
f.BoolVarP(&globalOptions.Quiet, "quiet", "q", false, "do not output comprehensive progress report")
f.CountVarP(&globalOptions.Verbose, "verbose", "v", "be verbose (specify --verbose multiple times or level `n`)")
f.BoolVar(&globalOptions.NoLock, "no-lock", false, "do not lock the repo, this allows some operations on read-only repos")
f.BoolVarP(&globalOptions.JSON, "json", "", false, "set output mode to JSON for commands that support it")
f.StringVar(&globalOptions.CacheDir, "cache-dir", "", "set the cache directory")
f.StringVar(&globalOptions.CacheDir, "cache-dir", "", "set the cache directory. (default: use system default cache directory)")
f.BoolVar(&globalOptions.NoCache, "no-cache", false, "do not use a local cache")
f.StringSliceVar(&globalOptions.CACerts, "cacert", nil, "`file` to load root certificates from (default: use system certificates)")
f.StringVar(&globalOptions.TLSClientCert, "tls-client-cert", "", "path to a file containing PEM encoded TLS client certificate and private key")
@@ -176,7 +184,6 @@ func Printf(format string, args ...interface{}) {
_, err := fmt.Fprintf(globalOptions.stdout, format, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "unable to write to stdout: %v\n", err)
Exit(100)
}
}
@@ -217,7 +224,6 @@ func Warnf(format string, args ...interface{}) {
_, err := fmt.Fprintf(globalOptions.stderr, format, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "unable to write to stderr: %v\n", err)
Exit(100)
}
}
@@ -233,7 +239,23 @@ func Exitf(exitcode int, format string, args ...interface{}) {
}
// resolvePassword determines the password to be used for opening the repository.
func resolvePassword(opts GlobalOptions, env string) (string, error) {
func resolvePassword(opts GlobalOptions) (string, error) {
if opts.PasswordFile != "" && opts.PasswordCommand != "" {
return "", errors.Fatalf("Password file and command are mutually exclusive options")
}
if opts.PasswordCommand != "" {
args, err := backend.SplitShellStrings(opts.PasswordCommand)
if err != nil {
return "", err
}
cmd := exec.Command(args[0], args[1:]...)
cmd.Stderr = os.Stderr
output, err := cmd.Output()
if err != nil {
return "", err
}
return (strings.TrimSpace(string(output))), nil
}
if opts.PasswordFile != "" {
s, err := textfile.Read(opts.PasswordFile)
if os.IsNotExist(errors.Cause(err)) {
@@ -242,7 +264,7 @@ func resolvePassword(opts GlobalOptions, env string) (string, error) {
return strings.TrimSpace(string(s)), errors.Wrap(err, "Readfile")
}
if pwd := os.Getenv(env); pwd != "" {
if pwd := os.Getenv("RESTIC_PASSWORD"); pwd != "" {
return pwd, nil
}
@@ -350,7 +372,7 @@ func OpenRepository(opts GlobalOptions) (*repository.Repository, error) {
return nil, err
}
err = s.SearchKey(opts.ctx, opts.password, maxKeys)
err = s.SearchKey(opts.ctx, opts.password, maxKeys, opts.KeyHint)
if err != nil {
return nil, err
}
@@ -360,7 +382,9 @@ func OpenRepository(opts GlobalOptions) (*repository.Repository, error) {
if len(id) > 8 {
id = id[:8]
}
Verbosef("repository %v opened successfully, password is correct\n", id)
if !opts.JSON {
Verbosef("repository %v opened successfully, password is correct\n", id)
}
}
if opts.NoCache {
@@ -373,6 +397,10 @@ func OpenRepository(opts GlobalOptions) (*repository.Repository, error) {
return s, nil
}
if c.Created && !opts.JSON {
Verbosef("created new cache in %v\n", c.Base)
}
// start using the cache
s.UseCache(c)

View File

@@ -54,7 +54,7 @@ directories in an encrypted repository stored on different backends.
if c.Name() == "version" {
return nil
}
pwd, err := resolvePassword(globalOptions, "RESTIC_PASSWORD")
pwd, err := resolvePassword(globalOptions)
if err != nil {
fmt.Fprintf(os.Stderr, "Resolving password failed: %v\n", err)
Exit(1)

View File

@@ -1,63 +0,0 @@
package main
import (
"fmt"
"io"
"strings"
)
// Table contains data for a table to be printed.
type Table struct {
Header string
Rows [][]interface{}
Footer string
RowFormat string
}
// NewTable initializes a new Table.
func NewTable() Table {
return Table{
Rows: [][]interface{}{},
}
}
func (t Table) printSeparationLine(w io.Writer) error {
_, err := fmt.Fprintln(w, strings.Repeat("-", 70))
return err
}
// Write prints the table to w.
func (t Table) Write(w io.Writer) error {
_, err := fmt.Fprintln(w, t.Header)
if err != nil {
return err
}
err = t.printSeparationLine(w)
if err != nil {
return err
}
for _, row := range t.Rows {
_, err = fmt.Fprintf(w, t.RowFormat+"\n", row...)
if err != nil {
return err
}
}
err = t.printSeparationLine(w)
if err != nil {
return err
}
_, err = fmt.Fprintln(w, t.Footer)
if err != nil {
return err
}
return nil
}
// TimeFormat is the format used for all timestamps printed by restic.
const TimeFormat = "2006-01-02 15:04:05"

72
contrib/restic.spec Normal file
View File

@@ -0,0 +1,72 @@
Name: restic
Version: 0.9.2git.20180812
Release: 4%{?dist}
Summary: restic is a backup program that is fast, efficient and secure.
%global debug_package %{nil}
Group: Applications/Archiving
License: BSD 2-Clause
URL: https://restic.net/
Source0: %{name}-%{version}.tar.gz
BuildRequires: golang
Requires: /bin/bash
%description
restic is a program that does backups right. The design goals are:
Easy: Doing backups should be a frictionless process, otherwise you are tempted to skip it. Restic should be easy to configure and use, so that in the unlikely event of a data loss you can just restore it. Likewise, restoring data should not be complicated.
Fast: Backing up your data with restic should only be limited by your network or hard disk bandwidth so that you can backup your files every day. Nobody does backups if it takes too much time. Restoring backups should only transfer data that is needed for the files that are to be restored, so that this process is also fast.
Verifiable: Much more important than backup is restore, so restic enables you to easily verify that all data can be restored.
Secure: Restic uses cryptography to guarantee confidentiality and integrity of your data. The location where the backup data is stored is assumed to be an untrusted environment (e.g. a shared space where others like system administrators are able to access your backups). Restic is built to secure your data against such attackers, by encrypting it with AES-256 in counter mode and authenticating it using Poly1305-AES.
Efficient: With the growth of data, additional snapshots should only take the storage of the actual increment. Even more, duplicate data should be de-duplicated before it is actually written to the storage backend to save precious backup space.
Versatile storage: Users can provide many different places to store the backups. Local, SFTP, Restics REST-Server, Amazon S3, Minio, Openstack Swift, Backblaze B2, Microsoft Azure Blob Storage, Google Cloud Storage and more by the usage of rclone.
Free: restic is free software and licensed under the BSD 2-Clause License and actively developed on GitHub.
%prep
%setup -q
%build
make %{?_smp_mflags}
%install
mkdir -p %{buildroot}%{_bindir}
mkdir -p %{buildroot}%{_mandir}/man1
mkdir -p %{buildroot}%{_datarootdir}/zsh/site-functions
mkdir -p %{buildroot}%{_datarootdir}/bash-completion/completions
install -p -m 644 doc/man/* %{buildroot}%{_mandir}/man1/
install -p -m 644 doc/zsh-completion.zsh %{buildroot}%{_datarootdir}/zsh/site-functions/_restic
install -p -m 644 doc/bash-completion.sh %{buildroot}%{_datarootdir}/bash-completion/completions/restic
install -p -m 755 %{name} %{buildroot}%{_bindir}
%files
%doc LICENSE
%doc README.rst
%{_bindir}/%{name}
%dir %{_datadir}/zsh/site-functions
%{_datadir}/zsh/site-functions/_restic
%dir %{_datadir}/bash-completion/
%dir %{_datadir}/bash-completion/completions
%{_datadir}/bash-completion/completions/restic
%{_mandir}/man1/restic*.*
%changelog
* Sun Aug 12 2018 Luc De Louw <luc@delouw.ch> - 0.9.2git.20180812-4
- %license does not work with RHEL6, using %doc instead
* Sun Aug 12 2018 Luc De Louw <luc@delouw.ch> - 0.9.2git.20180812-3
- Better description
* Sun Aug 12 2018 Luc De Louw <luc@delouw.ch> - 0.9.2git.20180812-2
- Initial RPM build
* Sun Aug 12 2018 Luc De Louw <luc@delouw.ch> - 0.9.2git.20180812-1
- Initial RPM build

11
doc.go Normal file
View File

@@ -0,0 +1,11 @@
// Package restic gives a (very brief) introduction to the structure of source code.
//
// Overview
//
// The packages are structured so that cmd/ contains the main package for the
// restic binary, and internal/ contains almost all code in library form. We've
// chosen to use the internal/ path so that the packages cannot be imported by
// other programs. This was done on purpose, at the moment restic is a
// command-line program and not a library. This may be revisited at a later
// point in time.
package restic

2
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
_build
.doctrees

View File

@@ -24,37 +24,18 @@ These are up to date binaries, built in a reproducible and verifiable way, that
you can download and run without having to do additional installation work.
Please see the :ref:`official_binaries` section below for various downloads.
Mac OS X
========
If you are using Mac OS X, you can install restic using the
`homebrew <http://brew.sh/>`__ package manager:
.. code-block:: console
$ brew install restic
Official binaries can be updated in place by using the ``restic self-update``
command.
Arch Linux
==========
On `Arch Linux <https://www.archlinux.org/>`__, there is a package called ``restic-git``
which can be installed from AUR, e.g. with ``pacaur``:
On `Arch Linux <https://www.archlinux.org/>`__, there is a package called ``restic``
installed from the official community repos, e.g. with ``pacman -S``:
.. code-block:: console
$ pacaur -S restic-git
Nix & NixOS
===========
If you are using `Nix <https://nixos.org/nix/>`__ or `NixOS <https://nixos.org/>`__
there is a package available named ``restic``.
It can be installed uisng ``nix-env``:
.. code-block:: console
$ nix-env --install restic
$ pacman -S restic
Debian
======
@@ -70,7 +51,62 @@ installed from the official repos, e.g. with ``apt-get``:
.. warning:: Please be aware that, at the time of writing, Debian *stable*
has ``restic`` version 0.3.3 which is very old. The *testing* and *unstable*
branches have recent versions of ``restic``.
Fedora
======
restic can be installed using ``dnf``:
.. code-block:: console
$ dnf install restic
If you used restic from copr previously, remove the copr repo as follows to
avoid any conflicts:
.. code-block:: console
$ dnf copr remove copart/restic
macOS
=====
If you are using macOS, you can install restic using the
`homebrew <https://brew.sh/>`__ package manager:
.. code-block:: console
$ brew install restic
Nix & NixOS
===========
If you are using `Nix <https://nixos.org/nix/>`__ or `NixOS <https://nixos.org/>`__
there is a package available named ``restic``.
It can be installed using ``nix-env``:
.. code-block:: console
$ nix-env --install restic
OpenBSD
=======
On OpenBSD 6.3 and greater, you can install restic using ``pkg_add``:
.. code-block:: console
# pkg_add restic
FreeBSD
=======
On FreeBSD (11 and probably later versions), you can install restic using ``pkg install``:
.. code-block:: console
# pkg install restic
RHEL & CentOS
=============
@@ -94,17 +130,6 @@ For CentOS7 use:
$ yum-config-manager --add-repo https://copr.fedorainfracloud.org/coprs/copart/restic/repo/epel-7/copart-restic-epel-7.repo
Fedora
======
restic can be installed via copr repository.
.. code-block:: console
$ dnf install dnf-plugin-core
$ dnf copr enable copart/restic
$ dnf install restic
Solus
=====
@@ -113,15 +138,19 @@ restic can be installed from the official repo of Solus via the ``eopkg`` packag
.. code-block:: console
$ eopkg install restic
OpenBSD
Windows
=======
On OpenBSD 6.3 and greater, you can install restic using ``pkg_add``:
restic can be installed using `Scoop <https://scoop.sh/>`__:
.. code-block:: console
# pkg_add restic
scoop install restic
Using this installation method, ``restic.exe`` will automatically be available
in the ``PATH``. It can be called from cmd.exe or PowerShell by typing ``restic``.
.. _official_binaries:
@@ -138,6 +167,38 @@ are considered stable and releases are made regularly in a controlled manner.
There's both pre-compiled binaries for different platforms as well as the source
code available for download. Just download and run the one matching your system.
The official binaries can be updated in place using the ``restic self-update``
command:
.. code-block:: console
$ restic version
restic 0.9.1 compiled with go1.10.3 on linux/amd64
$ restic self-update
find latest release of restic at GitHub
latest version is 0.9.2
download file SHA256SUMS
download SHA256SUMS
download file SHA256SUMS
download SHA256SUMS.asc
GPG signature verification succeeded
download restic_0.9.2_linux_amd64.bz2
downloaded restic_0.9.2_linux_amd64.bz2
saved 12115904 bytes in ./restic
successfully updated restic to version 0.9.2
$ restic version
restic 0.9.2 compiled with go1.10.3 on linux/amd64
The ``self-update`` command uses the GPG signature on the files uploaded to
GitHub to verify their authenticity. No external programs are necessary.
.. note:: Please be aware that the user executing the ``restic self-update``
command must have the permission to replace the restic binary.
If you want to save the downloaded restic binary into a different file, pass
the file name via the option ``--output``.
Unstable Builds
===============
@@ -187,6 +248,13 @@ In order to build restic from source, execute the following steps:
$ cd restic
$ go run -mod=vendor build.go
For Go versions < 1.11, the option ``-mod=vendor`` needs to be removed, like
this:
.. code-block:: console
$ go run build.go
You can easily cross-compile restic for all supported platforms, just
@@ -195,12 +263,14 @@ supply the target OS and platform via the command-line options like this
.. code-block:: console
$ go run build.go --goos windows --goarch amd64
$ go run -mod=vendor build.go --goos windows --goarch amd64
$ go run build.go --goos freebsd --goarch 386
$ go run -mod=vendor build.go --goos freebsd --goarch 386
$ go run -mod=vendor build.go --goos linux --goarch arm --goarm 6
Again, for Go < 1.11 ``-mod=vendor`` needs to be removed.
$ go run build.go --goos linux --goarch arm --goarm 6
The resulting binary is statically linked and does not require any
libraries.

View File

@@ -21,6 +21,19 @@ using a local repository; the remaining sections of this chapter cover all the
other options. You can skip to the next chapter once you've read the relevant
section here.
For automated backups, restic accepts the repository location in the
environment variable ``RESTIC_REPOSITORY``. For the password, several options
exist:
* Setting the environment variable ``RESTIC_PASSWORD``
* Specifying the path to a file with the password via the option
``--password-file`` or the environment variable ``RESTIC_PASSWORD_FILE``
* Configuring a program to be called when the password is needed via the
option ``--password-command`` or the environment variable
``RESTIC_PASSWORD_COMMAND``
Local
*****
@@ -41,11 +54,6 @@ command and enter the same password twice:
Remembering your password is important! If you lose it, you won't be
able to access data stored in the repository.
For automated backups, restic accepts the repository location in the
environment variable ``RESTIC_REPOSITORY``. The password can be read
from a file (via the option ``--password-file`` or the environment variable
``RESTIC_PASSWORD_FILE``) or the environment variable ``RESTIC_PASSWORD``.
SFTP
****
@@ -298,10 +306,10 @@ dashboard in on the "Buckets" page when signed into your B2 account:
.. code-block:: console
$ export B2_ACCOUNT_ID=<MY_ACCOUNT_ID>
$ export B2_ACCOUNT_ID=<MY_APPLICATION_KEY_ID>
$ export B2_ACCOUNT_KEY=<MY_SECRET_ACCOUNT_KEY>
.. note:: In case you want to use Backblaze Application Keys replace <MY_ACCOUNT_ID> and <MY_SECRET_ACCOUNT_KEY> with <applicationKeyId> and <applicationKey> respectively.
.. note:: In case you want to use Backblaze Application Keys replace <MY_APPLICATION_KEY_ID> and <MY_SECRET_ACCOUNT_KEY> with <applicationKeyId> and <applicationKey> respectively.
You can then initialize a repository stored at Backblaze B2. If the
bucket does not exist yet and the credentials you passed to restic have the

View File

@@ -33,18 +33,26 @@ again:
processed 1.720 GiB in 0:12
Files: 5307 new, 0 changed, 0 unmodified
Dirs: 1867 new, 0 changed, 0 unmodified
Added: 1.700 GiB
Added: 1.200 GiB
snapshot 40dc1520 saved
As you can see, restic created a backup of the directory and was pretty
fast! The specific snapshot just created is identified by a sequence of
hexadecimal characters, ``40dc1520`` in this case.
If you don't pass the ``--verbose`` option, restic will print less data. You'll still get a nice live status display. Be aware that the live status shows the processed files and not the transferred data. Transferred volume might be lower (due to deduplication) or higher.
You can see that restic tells us it processed 1.720 GiB of data, this is the
size of the files and directories in ``~/work`` on the local file system. It
also tells us that only 1.200 GiB was added to the repository. This means that
some of the data was duplicate and restic was able to efficiently reduce it.
If you don't pass the ``--verbose`` option, restic will print less data. You'll
still get a nice live status display. Be aware that the live status shows the
processed files and not the transferred data. Transferred volume might be lower
(due to de-duplication) or higher.
If you run the command again, restic will create another snapshot of
your data, but this time it's even faster. This is de-duplication at
work!
your data, but this time it's even faster and no new data was added to the
repository (since all data is already there). This is de-duplication at work!
.. code-block:: console
@@ -113,13 +121,18 @@ can compute which parts of the files need to be saved. When you backup
the same directory again (maybe with new or changed files) restic will
find the old snapshot in the repo and by default only reads those files
that are new or have been modified since the last snapshot. This is
decided based on the modify date of the file in the file system.
decided based on the following attributes of the file in the file system:
* Type (file, symlink, or directory?)
* Modification time
* Size
* Inode number (internal number used to reference a file in a file system)
Now is a good time to run ``restic check`` to verify that all data
is properly stored in the repository. You should run this command regularly
to make sure the internal structure of the repository is free of errors.
Including and Excluding Files
Including and Excluding Files
*****************************
You can exclude folders and files by specifying exclude patterns, currently
@@ -179,7 +192,7 @@ For this, the special wildcard ``**`` can be used to match arbitrary
sub-directories: The pattern ``foo/**/bar`` matches:
* ``/dir1/foo/dir2/bar/file``
* ``/foo/bar/file``
* ``/foo/bar/file``
* ``/tmp/foo/bar``
By specifying the option ``--one-file-system`` you can instruct restic
@@ -191,9 +204,12 @@ backup ``/sys`` or ``/dev`` on a Linux system:
$ restic -r /srv/restic-repo backup --one-file-system /
.. note:: ``--one-file-system`` is currently unsupported on Windows, and will
cause the backup to immediately fail with an error.
By using the ``--files-from`` option you can read the files you want to
backup from a file. This is especially useful if a lot of files have to
be backed up that are not in the same folder or are maybe pre-filtered
backup from one or more files. This is especially useful if a lot of files have
to be backed up that are not in the same folder or are maybe pre-filtered
by other software.
For example maybe you want to backup files which have a name that matches a
@@ -314,3 +330,51 @@ some additional data in the repository, but the snapshot will never be
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.
Environment Variables
*********************
In addition to command-line options, restic supports passing various options in
environment variables. The following list of environment variables:
.. code-block:: console
RESTIC_REPOSITORY Location of repository (replaces -r)
RESTIC_PASSWORD_FILE Location of password file (replaces --password-file)
RESTIC_PASSWORD The actual password for the repository
AWS_ACCESS_KEY_ID Amazon S3 access key ID
AWS_SECRET_ACCESS_KEY Amazon S3 secret access key
ST_AUTH Auth URL for keystone v1 authentication
ST_USER Username for keystone v1 authentication
ST_KEY Password for keystone v1 authentication
OS_AUTH_URL Auth URL for keystone authentication
OS_REGION_NAME Region name for keystone authentication
OS_USERNAME Username for keystone authentication
OS_PASSWORD Password for keystone authentication
OS_TENANT_ID Tenant ID for keystone v2 authentication
OS_TENANT_NAME Tenant name for keystone v2 authentication
OS_USER_DOMAIN_NAME User domain name for keystone authentication
OS_PROJECT_NAME Project name for keystone authentication
OS_PROJECT_DOMAIN_NAME PRoject domain name for keystone authentication
OS_STORAGE_URL Storage URL for token authentication
OS_AUTH_TOKEN Auth token for token authentication
B2_ACCOUNT_ID Account ID or applicationKeyId for Backblaze B2
B2_ACCOUNT_KEY Account Key or applicationKey for Backblaze B2
AZURE_ACCOUNT_NAME Account name for Azure
AZURE_ACCOUNT_KEY Account key for Azure
GOOGLE_PROJECT_ID Project ID for Google Cloud Storage
GOOGLE_APPLICATION_CREDENTIALS Application Credentials for Google Cloud Storage (e.g. $HOME/.config/gs-secret-restic-key.json)
RCLONE_BWLIMIT rclone bandwidth limit

View File

@@ -66,7 +66,7 @@ backup with the intention to make you restore malicious data:
.. code-block:: console
$ sudo echo "boom" >> backup/index/d795ffa99a8ab8f8e42cec1f814df4e48b8f49129360fb57613df93739faee97
$ echo "boom" >> backup/index/d795ffa99a8ab8f8e42cec1f814df4e48b8f49129360fb57613df93739faee97
In order to detect these things, it is a good idea to regularly use the
``check`` command to test whether everything is alright, your precious

View File

@@ -68,7 +68,9 @@ command to serve the repository with FUSE:
Don't forget to umount after quitting!
Mounting repositories via FUSE is not possible on OpenBSD, Solaris/illumos
and Windows.
and Windows. For Linux, the ``fuse`` kernel module needs to be loaded. For
FreeBSD, you may need to install FUSE and load the kernel module (``kldload
fuse``).
Restic supports storage and preservation of hard links. However, since
hard links exist in the scope of a filesystem by definition, restoring

View File

@@ -168,8 +168,9 @@ The ``forget`` command accepts the following parameters:
this option (can be specified multiple times).
- ``--keep-within duration`` keep all snapshots which have been made within
the duration of the latest snapshot. ``duration`` needs to be a number of
years, months, and days, e.g. ``2y5m7d`` will keep all snapshots made in the
two years, five months, and seven days before the latest snapshot.
years, months, days, and hours, e.g. ``2y5m7d3h`` will keep all snapshots
made in the two years, five months, seven days, and three hours before the
latest snapshot.
Multiple policies will be ORed together so as to be as inclusive as possible
for keeping snapshots.

View File

@@ -22,7 +22,9 @@ The program can be built with debug support like this:
.. code-block:: console
$ go run build.go -tags debug
$ go run build.go -mod=vendor -tags debug
For Go < 1.11, the option ``-mod=vendor`` needs to be removed.
Afterwards, extensive debug messages are written to the file in
environment variable ``DEBUG_LOG``, e.g.:
@@ -83,7 +85,7 @@ back end is contained in `Design <https://restic.readthedocs.io/en/latest/design
If you'd like to start contributing to restic, but don't know exactly
what do to, have a look at this great article by Dave Cheney:
`Suggestions for contributing to an Open Source
project <http://dave.cheney.net/2016/03/12/suggestions-for-contributing-to-an-open-source-project>`__
project <https://dave.cheney.net/2016/03/12/suggestions-for-contributing-to-an-open-source-project>`__
A few issues have been tagged with the label ``help wanted``, you can
start looking at those:
https://github.com/restic/restic/labels/help%20wanted
@@ -111,7 +113,7 @@ Compatibility
Backward compatibility for backups is important so that our users are
always able to restore saved data. Therefore restic follows `Semantic
Versioning <http://semver.org>`__ to clearly define which versions are
Versioning <https://semver.org>`__ to clearly define which versions are
compatible. The repository and data structures contained therein are
considered the "Public API" in the sense of Semantic Versioning. This
goes for all released versions of restic, this may not be the case for
@@ -126,7 +128,7 @@ prior versions.
Building documentation
**********************
The restic documentation is built with `Sphinx <http://sphinx-doc.org>`__,
The restic documentation is built with `Sphinx <https://www.sphinx-doc.org>`__,
therefore building it locally requires a recent Python version and requirements listed in ``doc/requirements.txt``.
This example will guide you through the process using `virtualenv <https://virtualenv.pypa.io>`__:

View File

@@ -17,4 +17,9 @@ help:
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: autobuild
autobuild:
sphinx-autobuild -b html -i '.doctrees/*' . _build

View File

@@ -274,8 +274,9 @@ _restic_backup()
flags+=("--help")
flags+=("-h")
local_nonpersistent_flags+=("--help")
flags+=("--hostname=")
local_nonpersistent_flags+=("--hostname=")
flags+=("--host=")
two_word_flags+=("-H")
local_nonpersistent_flags+=("--host=")
flags+=("--one-file-system")
flags+=("-x")
local_nonpersistent_flags+=("--one-file-system")
@@ -295,12 +296,14 @@ _restic_backup()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -337,16 +340,20 @@ _restic_cache()
local_nonpersistent_flags+=("--help")
flags+=("--max-age=")
local_nonpersistent_flags+=("--max-age=")
flags+=("--no-size")
local_nonpersistent_flags+=("--no-size")
flags+=("--cacert=")
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -383,12 +390,14 @@ _restic_cat()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -433,12 +442,14 @@ _restic_check()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -477,12 +488,14 @@ _restic_diff()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -526,12 +539,14 @@ _restic_dump()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -561,6 +576,8 @@ _restic_find()
flags_with_completion=()
flags_completion=()
flags+=("--blob")
local_nonpersistent_flags+=("--blob")
flags+=("--help")
flags+=("-h")
local_nonpersistent_flags+=("--help")
@@ -579,23 +596,31 @@ _restic_find()
flags+=("--oldest=")
two_word_flags+=("-O")
local_nonpersistent_flags+=("--oldest=")
flags+=("--pack")
local_nonpersistent_flags+=("--pack")
flags+=("--path=")
local_nonpersistent_flags+=("--path=")
flags+=("--show-pack-id")
local_nonpersistent_flags+=("--show-pack-id")
flags+=("--snapshot=")
two_word_flags+=("-s")
local_nonpersistent_flags+=("--snapshot=")
flags+=("--tag=")
local_nonpersistent_flags+=("--tag=")
flags+=("--tree")
local_nonpersistent_flags+=("--tree")
flags+=("--cacert=")
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -649,8 +674,6 @@ _restic_forget()
local_nonpersistent_flags+=("--keep-tag=")
flags+=("--host=")
local_nonpersistent_flags+=("--host=")
flags+=("--hostname=")
local_nonpersistent_flags+=("--hostname=")
flags+=("--tag=")
local_nonpersistent_flags+=("--tag=")
flags+=("--path=")
@@ -673,12 +696,14 @@ _restic_forget()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -721,12 +746,14 @@ _restic_generate()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -763,12 +790,14 @@ _restic_init()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -807,12 +836,14 @@ _restic_key()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -849,12 +880,14 @@ _restic_list()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -895,18 +928,22 @@ _restic_ls()
local_nonpersistent_flags+=("--long")
flags+=("--path=")
local_nonpersistent_flags+=("--path=")
flags+=("--recursive")
local_nonpersistent_flags+=("--recursive")
flags+=("--tag=")
local_nonpersistent_flags+=("--tag=")
flags+=("--cacert=")
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -946,12 +983,14 @@ _restic_migrate()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -991,6 +1030,8 @@ _restic_mount()
flags+=("--host=")
two_word_flags+=("-H")
local_nonpersistent_flags+=("--host=")
flags+=("--no-default-permissions")
local_nonpersistent_flags+=("--no-default-permissions")
flags+=("--owner-root")
local_nonpersistent_flags+=("--owner-root")
flags+=("--path=")
@@ -1003,12 +1044,14 @@ _restic_mount()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1045,12 +1088,14 @@ _restic_prune()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1087,12 +1132,58 @@ _restic_rebuild-index()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
flags+=("-q")
flags+=("--repo=")
two_word_flags+=("-r")
flags+=("--tls-client-cert=")
flags+=("--verbose")
flags+=("-v")
must_have_one_flag=()
must_have_one_noun=()
noun_aliases=()
}
_restic_recover()
{
last_command="restic_recover"
command_aliases=()
commands=()
flags=()
two_word_flags=()
local_nonpersistent_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
local_nonpersistent_flags+=("--help")
flags+=("--cacert=")
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1147,12 +1238,60 @@ _restic_restore()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
flags+=("-q")
flags+=("--repo=")
two_word_flags+=("-r")
flags+=("--tls-client-cert=")
flags+=("--verbose")
flags+=("-v")
must_have_one_flag=()
must_have_one_noun=()
noun_aliases=()
}
_restic_self-update()
{
last_command="restic_self-update"
command_aliases=()
commands=()
flags=()
two_word_flags=()
local_nonpersistent_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
local_nonpersistent_flags+=("--help")
flags+=("--output=")
local_nonpersistent_flags+=("--output=")
flags+=("--cacert=")
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1201,12 +1340,14 @@ _restic_snapshots()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1240,6 +1381,7 @@ _restic_stats()
flags+=("-h")
local_nonpersistent_flags+=("--help")
flags+=("--host=")
two_word_flags+=("-H")
local_nonpersistent_flags+=("--host=")
flags+=("--mode=")
local_nonpersistent_flags+=("--mode=")
@@ -1247,12 +1389,14 @@ _restic_stats()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1302,12 +1446,14 @@ _restic_tag()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1346,12 +1492,14 @@ _restic_unlock()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1388,12 +1536,14 @@ _restic_version()
flags+=("--cache-dir=")
flags+=("--cleanup-cache")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")
@@ -1433,7 +1583,9 @@ _restic_root_command()
commands+=("mount")
commands+=("prune")
commands+=("rebuild-index")
commands+=("recover")
commands+=("restore")
commands+=("self-update")
commands+=("snapshots")
commands+=("stats")
commands+=("tag")
@@ -1453,12 +1605,14 @@ _restic_root_command()
flags+=("-h")
local_nonpersistent_flags+=("--help")
flags+=("--json")
flags+=("--key-hint=")
flags+=("--limit-download=")
flags+=("--limit-upload=")
flags+=("--no-cache")
flags+=("--no-lock")
flags+=("--option=")
two_word_flags+=("-o")
flags+=("--password-command=")
flags+=("--password-file=")
two_word_flags+=("-p")
flags+=("--quiet")

View File

@@ -9,8 +9,8 @@ Versions
========
The cache directory is selected according to the `XDG base dir specification
<http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>`__.
Each repository has its own cache sub-directory, consting of the repository ID
<https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>`__.
Each repository has its own cache sub-directory, consisting of the repository ID
which is chosen at ``init``. All cache directories for different repos are
independent of each other.

View File

@@ -276,7 +276,7 @@ the IV for counter mode and the nonce for Poly1305. This operation needs
three keys: A 32 byte for AES-256 for encryption, a 16 byte AES key and
a 16 byte key for Poly1305. For details see the original paper `The
Poly1305-AES message-authentication
code <http://cr.yp.to/mac/poly1305-20050329.pdf>`__ by Dan Bernstein.
code <https://cr.yp.to/mac/poly1305-20050329.pdf>`__ by Dan Bernstein.
The data is then encrypted with AES-256 and afterwards a message
authentication code (MAC) is computed over the ciphertext, everything is
then stored as IV \|\| CIPHERTEXT \|\| MAC.

View File

@@ -0,0 +1,123 @@
Developer Information
#####################
Reproducible Builds
*******************
This section describes how to reproduce the official released binaries for
restic for version 0.9.3 and later. The binary produced depends on the
following things:
* The source code for the release
* The exact version of the official `Go compiler <https://golang.org>`__ used to produce the binaries (running ``restic version`` will print this)
* The architecture and operating system the Go compiler runs on (Linux, ``amd64``)
* The path where the source code is extracted to (``/restic``)
* The path to the Go compiler (``/usr/local/go``)
* The build tags (for official binaries, it's the tag ``selfupdate``)
* The environment variables (mostly ``$GOOS``, ``$GOARCH``, ``$CGO_ENABLED``)
In addition, The compressed ZIP files for Windows depends on the modification
timestamp of the binary contained in it. In order to reproduce the exact same
ZIP file every time, we update the timestamp of the file ``VERSION`` in the
source code archive and set the timezone to Europe/Berlin.
In the following example, we'll use the file ``restic-0.9.3.tar.gz`` and Go
1.11.1 to reproduce the released binaries.
1. Download and extract the Go compiler into ``/usr/local/go``:
.. code::
$ cd /usr/local
$ curl -L https://dl.google.com/go/go1.11.1.linux-amd64.tar.gz | tar xz
2. Extract the restic source code into ``/restic``
.. code::
$ mkdir /restic
$ cd /restic
$ TZ=Europe/Berlin curl -L https://github.com/restic/restic/releases/download/v0.9.3/restic-0.9.3.tar.gz | tar xz --strip-components=1
3. Build the binaries for Windows and Linux:
.. code::
$ export PATH=/usr/local/go/bin:$PATH
$ go version
go version go1.11.1 linux/amd64
$ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -mod=vendor -ldflags "-s -w" -tags selfupdate -o restic_linux_amd64 ./cmd/restic
$ bzip2 restic_linux_amd64
$ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -mod=vendor -ldflags "-s -w" -tags selfupdate -o restic_windows_amd64.exe ./cmd/restic
$ touch --reference VERSION restic_windows_amd64.exe
$ TZ=Europe/Berlin zip -q -X restic_windows_amd64.zip restic_windows_amd64.exe
Building the Official Binaries
******************************
The released binaries for restic are built using a Docker container. You can
find it on `Docker Hub <https://hub.docker.com/r/restic/builder>`__ as
``restic/builder``, the ``Dockerfile`` and instructions on how to build the
container can be found in the `GitHub repository
<https://github.com/restic/builder>`__
The container serves the following goals:
* Have a very controlled environment which is independent from the local system
* Make it easy to have the correct version of the Go compiler at the right path
* Make it easy to pass in the source code to build at a well-defined path
The following steps are necessary to build the binaries:
1. Either build the container (see the instructions in the `repository's README <https://github.com/restic/builder>`__). Alternatively, download the container from the hub:
.. code::
docker pull restic/builder
2. Extract the source code somewhere:
.. code::
tar xvzf restic-0.9.3.tar.gz
3. Create a directory to place the resulting binaries in:
.. code::
mkdir output
3. Mount the source code and the output directory in the container and run the default command, which starts ``helpers/build-release-binaries/main.go``:
.. code::
docker run --rm \
--volume "$PWD/restic-0.9.3:/restic" \
--volume "$PWD/output:/output" \
restic/builder
4. If anything goes wrong, you can enable debug output by specifying the call to ``helpers/build-release-binaries/main.go`` like this:
.. code::
docker run --rm \
--volume "$PWD/restic-0.9.3:/restic" \
--volume "$PWD/output:/output" \
restic/builder \
go run -mod=vendor helpers/build-release-binaries/main.go --verbose
Prepare a New Release
*********************
Publishing a new release of restic requires many different steps. We've
automated this in the Go program ``helpers/prepare-release/main.go`` which also
includes checking that e.g. the changelog is correctly generated. The only
required argument is the new version number (in `Semantic Versioning
<https://semver.org/>`__ format ``MAJOR.MINOR.PATCH``):
.. code::
go run -mod=vendor helpers/prepare-release/main.go 0.9.3
Checks can be skipped on demand via flags, please see ``--help`` for details.

View File

@@ -27,6 +27,54 @@ strictly necessary. With high probability this is duplicate data. In
order to clean it up, the command ``restic prune`` can be used. The
cause of this bug is not yet known.
I ran a ``restic`` command but it is not working as intended, what do I do now?
-------------------------------------------------------------------------------
If you are running a restic command and it is not working as you hoped it would,
there is an easy way of checking how your shell interpreted the command you are trying to run.
Here is an example of a mistake in a backup command that results in the command not working as expected.
A user wants to run the following ``restic backup`` command
::
$ restic backup --exclude "~/documents" ~
.. important:: This command contains an intentional user error described in this paragraph.
This command will result in a complete backup of the current logged in user's home directory and it won't exclude the folder ``~/documents/`` - which is not what the user wanted to achieve.
The problem is how the path to ``~/documents`` is passed to restic.
In order to spot an issue like this, you can make use of the following ruby command preceding your restic command.
::
$ ruby -e 'puts ARGV.inspect' restic backup --exclude "~/documents" ~
["restic", "backup", "--exclude", "~/documents", "/home/john"]
As you can see, the command outputs every argument you have passed to the shell. This is what restic sees when you run your command.
The error here is that the tilde ``~`` in ``"~/documents"`` didn't get expanded as it is quoted.
::
$ echo ~/documents
/home/john/documents
$ echo "~/documents"
~/document
$ echo "$HOME/documents"
/home/john/documents
Restic handles globbing and expansion in the following ways:
- Globbing is only expanded for lines read via ``--files-from``
- Environment variables are not expanded in the file read via ``--files-from``
- ``*`` is expanded for paths read via ``--files-from``
- e.g. For backup targets given to restic as arguments on the shell, neither glob expansion nor shell variable replacement is done. If restic is called as ``restic backup '*' '$HOME'``, it will try to backup the literal file(s)/dir(s) ``*`` and ``$HOME``
- Double-asterisk ``**`` only works in exclude patterns as this is a custom extension built into restic; the shell must not expand it
How can I specify encryption passwords automatically?
-----------------------------------------------------
@@ -124,4 +172,4 @@ The following may work:
Why does restic perform so poorly on Windows?
---------------------------------------------
In some cases the realtime protection of antivirus software can interfere with restic's operations. If you are experiencing bad performace you can try to temporarily disable your antivirus software to find out if it is the cause for your performance problems.
In some cases the real-time protection of antivirus software can interfere with restic's operations. If you are experiencing bad performance you can try to temporarily disable your antivirus software to find out if it is the cause for your performance problems.

View File

@@ -19,3 +19,4 @@ Restic Documentation
110_talks
faq
manual_rest
developer_information

View File

@@ -37,8 +37,8 @@ given as the arguments.
takes filename[:header], exclude contents of directories containing filename (except filename itself) if header of that file is as provided (can be specified multiple times)
.PP
\fB\-\-files\-from\fP=""
read the files to backup from file (can be combined with file args)
\fB\-\-files\-from\fP=[]
read the files to backup from file (can be combined with file args/can be specified multiple times)
.PP
\fB\-f\fP, \fB\-\-force\fP[=false]
@@ -49,7 +49,7 @@ given as the arguments.
help for backup
.PP
\fB\-\-hostname\fP=""
\fB\-H\fP, \fB\-\-host\fP=""
set the \fB\fChostname\fR for the snapshot manually. To prevent an expensive rescan use the "parent" flag
.PP
@@ -88,7 +88,7 @@ given as the arguments.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -98,6 +98,10 @@ given as the arguments.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -118,6 +122,10 @@ given as the arguments.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -31,6 +31,10 @@ The "cache" command allows listing and cleaning local cache directories.
\fB\-\-max\-age\fP=30
max age in \fB\fCdays\fR for cache directories to be considered old
.PP
\fB\-\-no\-size\fP[=false]
do not output the size of the cache directories
.SH OPTIONS INHERITED FROM PARENT COMMANDS
.PP
@@ -39,7 +43,7 @@ The "cache" command allows listing and cleaning local cache directories.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -49,6 +53,10 @@ The "cache" command allows listing and cleaning local cache directories.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -69,6 +77,10 @@ The "cache" command allows listing and cleaning local cache directories.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -31,7 +31,7 @@ The "cat" command is used to print internal objects to stdout.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -41,6 +41,10 @@ The "cat" command is used to print internal objects to stdout.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -61,6 +65,10 @@ The "cat" command is used to print internal objects to stdout.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -52,7 +52,7 @@ repository and not use a local cache.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -62,6 +62,10 @@ repository and not use a local cache.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -82,6 +86,10 @@ repository and not use a local cache.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -21,11 +21,14 @@ directory:
.RS
.IP \(bu 2
The item was added
+ The item was added
.IP \(bu 2
\- The item was removed
.IP \(bu 2
The item was removed
U The metadata (access mode, timestamps, ...) for the item was updated
.IP \(bu 2
M The file's content was modified
.IP \(bu 2
T The type was changed, e.g. a file was made a symlink
.RE
@@ -48,7 +51,7 @@ T The type was changed, e.g. a file was made a symlink
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -58,6 +61,10 @@ T The type was changed, e.g. a file was made a symlink
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -78,6 +85,10 @@ T The type was changed, e.g. a file was made a symlink
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -48,7 +48,7 @@ repository.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -58,6 +58,10 @@ repository.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -78,6 +82,10 @@ repository.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -5,21 +5,26 @@
.SH NAME
.PP
restic\-find \- Find a file or directory
restic\-find \- Find a file, a directory or restic IDs
.SH SYNOPSIS
.PP
\fBrestic find [flags] PATTERN\fP
\fBrestic find [flags] PATTERN...\fP
.SH DESCRIPTION
.PP
The "find" command searches for files or directories in snapshots stored in the
repo.
It can also be used to search for restic blobs or trees for troubleshooting.
.SH OPTIONS
.PP
\fB\-\-blob\fP[=false]
pattern is a blob\-ID
.PP
\fB\-h\fP, \fB\-\-help\fP[=false]
help for find
@@ -44,10 +49,18 @@ repo.
\fB\-O\fP, \fB\-\-oldest\fP=""
oldest modification date/time
.PP
\fB\-\-pack\fP[=false]
pattern is a pack\-ID
.PP
\fB\-\-path\fP=[]
only consider snapshots which include this (absolute) \fB\fCpath\fR, when no snapshot\-ID is given
.PP
\fB\-\-show\-pack\-id\fP[=false]
display the pack\-ID the blobs belong to (with \-\-blob)
.PP
\fB\-s\fP, \fB\-\-snapshot\fP=[]
snapshot \fB\fCid\fR to search in (can be given multiple times)
@@ -56,6 +69,10 @@ repo.
\fB\-\-tag\fP=[]
only consider snapshots which include this \fB\fCtaglist\fR, when no snapshot\-ID is given
.PP
\fB\-\-tree\fP[=false]
pattern is a tree\-ID
.SH OPTIONS INHERITED FROM PARENT COMMANDS
.PP
@@ -64,7 +81,7 @@ repo.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -74,6 +91,10 @@ repo.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -94,6 +115,10 @@ repo.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)
@@ -115,6 +140,22 @@ repo.
be verbose (specify \-\-verbose multiple times or level \fB\fCn\fR)
.SH EXAMPLE
.PP
.RS
.nf
restic find config.json
restic find \-\-json "*.yml" "*.json"
restic find \-\-json \-\-blob 420f620f b46ebe8a ddd38656
restic find \-\-show\-pack\-id \-\-blob 420f620f
restic find \-\-tree 577c2bc9 f81f2e22 a62827a9
restic find \-\-pack 025c1d06
.fi
.RE
.SH SEE ALSO
.PP
\fBrestic(1)\fP

View File

@@ -48,7 +48,7 @@ data after 'forget' was run successfully, see the 'prune' command.
.PP
\fB\-\-keep\-within\fP=
keep snapshots that were created within \fB\fCduration\fR before the newest (e.g. 1y5m7d)
keep snapshots that are newer than \fB\fCduration\fR (eg. 1y5m7d2h) relative to the latest snapshot
.PP
\fB\-\-keep\-tag\fP=[]
@@ -58,10 +58,6 @@ data after 'forget' was run successfully, see the 'prune' command.
\fB\-\-host\fP=""
only consider snapshots with the given \fB\fChost\fR
.PP
\fB\-\-hostname\fP=""
only consider snapshots with the given \fB\fChostname\fR (deprecated)
.PP
\fB\-\-tag\fP=[]
only consider snapshots which include this \fB\fCtaglist\fR in the format \fB\fCtag[,tag,...]\fR (can be specified multiple times)
@@ -98,7 +94,7 @@ data after 'forget' was run successfully, see the 'prune' command.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -108,6 +104,10 @@ data after 'forget' was run successfully, see the 'prune' command.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -128,6 +128,10 @@ data after 'forget' was run successfully, see the 'prune' command.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -44,7 +44,7 @@ and the auto\-completion files for bash and zsh).
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -54,6 +54,10 @@ and the auto\-completion files for bash and zsh).
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -74,6 +78,10 @@ and the auto\-completion files for bash and zsh).
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -31,7 +31,7 @@ The "init" command initializes a new repository.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -41,6 +41,10 @@ The "init" command initializes a new repository.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -61,6 +65,10 @@ The "init" command initializes a new repository.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -35,7 +35,7 @@ The "key" command manages keys (passwords) for accessing the repository.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -45,6 +45,10 @@ The "key" command manages keys (passwords) for accessing the repository.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -65,6 +69,10 @@ The "key" command manages keys (passwords) for accessing the repository.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -31,7 +31,7 @@ The "list" command allows listing objects in the repository based on type.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -41,6 +41,10 @@ The "list" command allows listing objects in the repository based on type.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -61,6 +65,10 @@ The "list" command allows listing objects in the repository based on type.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -10,15 +10,27 @@ restic\-ls \- List files in a snapshot
.SH SYNOPSIS
.PP
\fBrestic ls [flags] [snapshot\-ID ...]\fP
\fBrestic ls [flags] [snapshotID] [dir...]\fP
.SH DESCRIPTION
.PP
The "ls" command allows listing files and directories in a snapshot.
The "ls" command lists files and directories in a snapshot.
.PP
The special snapshot\-ID "latest" can be used to list files and directories of the latest snapshot in the repository.
The special snapshot ID "latest" can be used to list files and
directories of the latest snapshot in the repository. The
\-\-host flag can be used in conjunction to select the latest
snapshot originating from a certain host only.
.PP
File listings can optionally be filtered by directories. Any
positional arguments after the snapshot ID are interpreted as
absolute directory paths, and only files inside those directories
will be listed. If the \-\-recursive flag is used, then the filter
will allow traversing into matching directories' subfolders.
Any directory paths specified must be absolute (starting with
a path separator); paths use the forward slash '/' as separator.
.SH OPTIONS
@@ -38,6 +50,10 @@ The special snapshot\-ID "latest" can be used to list files and directories of t
\fB\-\-path\fP=[]
only consider snapshots which include this (absolute) \fB\fCpath\fR, when no snapshot ID is given
.PP
\fB\-\-recursive\fP[=false]
include files in subfolders of the listed directories
.PP
\fB\-\-tag\fP=[]
only consider snapshots which include this \fB\fCtaglist\fR, when no snapshot ID is given
@@ -50,7 +66,7 @@ The special snapshot\-ID "latest" can be used to list files and directories of t
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -60,6 +76,10 @@ The special snapshot\-ID "latest" can be used to list files and directories of t
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -80,6 +100,10 @@ The special snapshot\-ID "latest" can be used to list files and directories of t
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -36,7 +36,7 @@ name is explicitly given, a list of migrations that can be applied is printed.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -46,6 +46,10 @@ name is explicitly given, a list of migrations that can be applied is printed.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -66,6 +70,10 @@ name is explicitly given, a list of migrations that can be applied is printed.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -68,6 +68,10 @@ For details please see the documentation for time.Format() at:
\fB\-H\fP, \fB\-\-host\fP=""
only consider snapshots for this host
.PP
\fB\-\-no\-default\-permissions\fP[=false]
for 'allow\-other', ignore Unix permissions and allow users to read all snapshot files
.PP
\fB\-\-owner\-root\fP[=false]
use 'root' as the owner of files and dirs
@@ -92,7 +96,7 @@ For details please see the documentation for time.Format() at:
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -102,6 +106,10 @@ For details please see the documentation for time.Format() at:
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -122,6 +130,10 @@ For details please see the documentation for time.Format() at:
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -32,7 +32,7 @@ referenced and therefore not needed any more.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -42,6 +42,10 @@ referenced and therefore not needed any more.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -62,6 +66,10 @@ referenced and therefore not needed any more.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -32,7 +32,7 @@ repository.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -42,6 +42,10 @@ repository.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -62,6 +66,10 @@ repository.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

97
doc/man/restic-recover.1 Normal file
View File

@@ -0,0 +1,97 @@
.TH "restic backup" "1" "Jan 2017" "generated by `restic generate`" ""
.nh
.ad l
.SH NAME
.PP
restic\-recover \- Recover data from the repository
.SH SYNOPSIS
.PP
\fBrestic recover [flags]\fP
.SH DESCRIPTION
.PP
The "recover" command build a new snapshot from all directories it can find in
the raw data of the repository. It can be used if, for example, a snapshot has
been removed by accident with "forget".
.SH OPTIONS
.PP
\fB\-h\fP, \fB\-\-help\fP[=false]
help for recover
.SH OPTIONS INHERITED FROM PARENT COMMANDS
.PP
\fB\-\-cacert\fP=[]
\fB\fCfile\fR to load root certificates from (default: use system certificates)
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
auto remove old cache directories
.PP
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
.PP
\fB\-\-limit\-upload\fP=0
limits uploads to a maximum rate in KiB/s. (default: unlimited)
.PP
\fB\-\-no\-cache\fP[=false]
do not use a local cache
.PP
\fB\-\-no\-lock\fP[=false]
do not lock the repo, this allows some operations on read\-only repos
.PP
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (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=""
repository to backup to or restore from (default: $RESTIC\_REPOSITORY)
.PP
\fB\-\-tls\-client\-cert\fP=""
path to a file containing PEM encoded TLS client certificate and private key
.PP
\fB\-v\fP, \fB\-\-verbose\fP[=0]
be verbose (specify \-\-verbose multiple times or level \fB\fCn\fR)
.SH SEE ALSO
.PP
\fBrestic(1)\fP

View File

@@ -64,7 +64,7 @@ repository.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -74,6 +74,10 @@ repository.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -94,6 +98,10 @@ repository.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -0,0 +1,102 @@
.TH "restic backup" "1" "Jan 2017" "generated by `restic generate`" ""
.nh
.ad l
.SH NAME
.PP
restic\-self\-update \- Update the restic binary
.SH SYNOPSIS
.PP
\fBrestic self\-update [flags]\fP
.SH DESCRIPTION
.PP
The command "self\-update" downloads the latest stable release of restic from
GitHub and replaces the currently running binary. After download, the
authenticity of the binary is verified using the GPG signature on the release
files.
.SH OPTIONS
.PP
\fB\-h\fP, \fB\-\-help\fP[=false]
help for self\-update
.PP
\fB\-\-output\fP=""
Save the downloaded file as \fB\fCfilename\fR (default: running binary itself)
.SH OPTIONS INHERITED FROM PARENT COMMANDS
.PP
\fB\-\-cacert\fP=[]
\fB\fCfile\fR to load root certificates from (default: use system certificates)
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
auto remove old cache directories
.PP
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
.PP
\fB\-\-limit\-upload\fP=0
limits uploads to a maximum rate in KiB/s. (default: unlimited)
.PP
\fB\-\-no\-cache\fP[=false]
do not use a local cache
.PP
\fB\-\-no\-lock\fP[=false]
do not lock the repo, this allows some operations on read\-only repos
.PP
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (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=""
repository to backup to or restore from (default: $RESTIC\_REPOSITORY)
.PP
\fB\-\-tls\-client\-cert\fP=""
path to a file containing PEM encoded TLS client certificate and private key
.PP
\fB\-v\fP, \fB\-\-verbose\fP[=0]
be verbose (specify \-\-verbose multiple times or level \fB\fCn\fR)
.SH SEE ALSO
.PP
\fBrestic(1)\fP

View File

@@ -51,7 +51,7 @@ The "snapshots" command lists all snapshots stored in the repository.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -61,6 +61,10 @@ The "snapshots" command lists all snapshots stored in the repository.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -81,6 +85,10 @@ The "snapshots" command lists all snapshots stored in the repository.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -29,23 +29,22 @@ to calculate.
.PP
The modes are:
.PP
.RS
.IP \(bu 2
restore\-size: (default) Counts the size of the restored files.
.PP
.IP \(bu 2
files\-by\-contents: Counts total size of files, where a file is
considered unique if it has unique contents.
.PP
raw\-data: Counts the size of blobs in the repository, regardless
of how many files reference them.
.PP
considered unique if it has unique contents.
.IP \(bu 2
raw\-data: Counts the size of blobs in the repository, regardless of
how many files reference them.
.IP \(bu 2
blobs\-per\-file: A combination of files\-by\-contents and raw\-data.
.PP
.IP \(bu 2
Refer to the online manual for more details about each mode.
.RE
.SH OPTIONS
.PP
@@ -53,7 +52,7 @@ Refer to the online manual for more details about each mode.
help for stats
.PP
\fB\-\-host\fP=""
\fB\-H\fP, \fB\-\-host\fP=""
filter latest snapshot by this hostname
.PP
@@ -68,7 +67,7 @@ Refer to the online manual for more details about each mode.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -78,6 +77,10 @@ Refer to the online manual for more details about each mode.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -98,6 +101,10 @@ Refer to the online manual for more details about each mode.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -62,7 +62,7 @@ When no snapshot\-ID is given, all snapshots matching the host, tag and path fil
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -72,6 +72,10 @@ When no snapshot\-ID is given, all snapshots matching the host, tag and path fil
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -92,6 +96,10 @@ When no snapshot\-ID is given, all snapshots matching the host, tag and path fil
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -35,7 +35,7 @@ The "unlock" command removes stale locks that have been created by other restic
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -45,6 +45,10 @@ The "unlock" command removes stale locks that have been created by other restic
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -65,6 +69,10 @@ The "unlock" command removes stale locks that have been created by other restic
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

View File

@@ -32,7 +32,7 @@ and the version of this software.
.PP
\fB\-\-cache\-dir\fP=""
set the cache directory
set the cache directory. (default: use system default cache directory)
.PP
\fB\-\-cleanup\-cache\fP[=false]
@@ -42,6 +42,10 @@ and the version of this software.
\fB\-\-json\fP[=false]
set output mode to JSON for commands that support it
.PP
\fB\-\-key\-hint\fP=""
key ID of key to try decrypting first (default: $RESTIC\_KEY\_HINT)
.PP
\fB\-\-limit\-download\fP=0
limits downloads to a maximum rate in KiB/s. (default: unlimited)
@@ -62,6 +66,10 @@ and the version of this software.
\fB\-o\fP, \fB\-\-option\fP=[]
set extended option (\fB\fCkey=value\fR, can be specified multiple times)
.PP
\fB\-\-password\-command\fP=""
specify a shell command to obtain a password (default: $RESTIC\_PASSWORD\_COMMAND)
.PP
\fB\-p\fP, \fB\-\-password\-file\fP=""
read the repository password from a file (default: $RESTIC\_PASSWORD\_FILE)

Some files were not shown because too many files have changed in this diff Show More