Compare commits

..

589 commits

Author SHA1 Message Date
Thomas Waldmann
4c131059bc
build_man 2023-12-02 01:02:03 +01:00
Thomas Waldmann
46c1e01d29
build_usage 2023-12-02 01:01:46 +01:00
Thomas Waldmann
8b70bb36c6
update CHANGES 2023-12-02 00:59:58 +01:00
TW
e50d26757c
Merge pull request #7956 from ThomasWaldmann/py313-unistdh-1.2
include unistd.h in _chunker.c
2023-12-02 00:44:59 +01:00
TW
d3e412c7c6
Merge pull request #7957 from ThomasWaldmann/docs-rebuild-refcounts-1.2
docs: Add "check.rebuild_refcounts" message
2023-12-02 00:23:25 +01:00
Sophie Herold
897f88dfaa
docs: Add "check.rebuild_refcounts" message 2023-12-02 00:01:12 +01:00
Felix Schwarz
13c6d1b710
include unistd.h in _chunker.c
With Python 3.13, Python.h no longer includes the <unistd.h> standard header file:
https://docs.python.org/3.13/whatsnew/3.13.html#id8
2023-12-01 23:58:24 +01:00
TW
b2929b4cee
Merge pull request #7952 from ThomasWaldmann/update-changes-1.2
update CHANGES (1.2-maint)
2023-11-29 16:48:38 +01:00
Kevin Yin
bcc8f74b56
Remove period that could be interpreted as part of the command (#7946)
CVE upgrade steps: remove period that could be interpreted as part of the command
2023-11-27 18:12:26 +01:00
Thomas Waldmann
4bdd404949
update CHANGES 2023-11-27 18:08:00 +01:00
TW
70eed5e9fc
Merge pull request #7939 from ThomasWaldmann/lockroster-remove-fix-1.2
LockRoster.modify fix (1.2-maint)
2023-11-18 17:35:22 +01:00
Thomas Waldmann
ec17b00411
LockRoster.modify: no KeyError if element was already gone, fixes #7937
The intention of LockRoster.modify(key, REMOVE) is to remove self.id.

Using set.discard will just ignore it if self.id is not present there anymore.

Previously, using set.remove triggered a KeyError that has been frequently
seen in tracebacks of teardowns involving Repository.__del__ and Repository.__exit__.

I added a REMOVE2 op to serve one caller that needs to get the KeyError if
self.id was not present.

Thanks to @herrmanntom for the workaround!
2023-11-16 15:59:28 +01:00
zDEFz
2cefe8f53d
Add backup by SERIAL method (#7934)
docs: create disk/partition sector backup by disk serial number
2023-11-13 22:03:09 +01:00
TW
2341ba62d3
Merge pull request #7926 from ThomasWaldmann/update-requirements-1.2
update requirements.d/development.lock.txt
2023-11-09 02:19:51 +01:00
Thomas Waldmann
f08386f699
update requirements.d/development.lock.txt 2023-11-09 00:46:12 +01:00
TW
4e349cf3fa
Merge pull request #7915 from ThomasWaldmann/fix-subcommand-env-1.2
create --*-from-command: run subcommands with a clean environment
2023-11-07 03:42:25 +01:00
Thomas Waldmann
e006a6f368
create --*-from-command: run subcommands with a clean environment, fixes #7916
When borg invokes a system command, it needs to prepare the environment
for that. This is especially important when using a pyinstaller-made
borg fat binary that works with a modified env var LD_LIBRARY_PATH -
system commands may crash with that.

borg already had calls to prepare_subprocess_env at some places (e.g.
when invoking ssh for the remote repo connection), but they were
missing for:

borg create --content-from-command ...
borg create --paths-from-command ...
2023-11-06 17:41:52 +01:00
TW
11af475308
Merge pull request #7913 from ThomasWaldmann/docs-upgrade-chkpt-tam-1.2
CVE-2023-36811 upgrade docs: consider checkpoint archives, fixes #7802
2023-11-06 14:30:36 +01:00
Thomas Waldmann
9c886330d3
CVE-2023-36811 upgrade docs: consider checkpoint archives, fixes #7802
The traceback seen there came from borg not showing a .checkpoint archive
that didn't have a valid TAM and thus the user not see it / fix it:

https://github.com/borgbackup/borg/issues/7802#issuecomment-1793860606
2023-11-06 13:31:02 +01:00
TW
21d67b8295
Merge pull request #7904 from ThomasWaldmann/fix-shadow-index2-1.2
shadow index: add more comments
2023-11-05 01:24:47 +01:00
Thomas Waldmann
2a2b750b9d
shadow index: add more comments 2023-11-05 01:22:07 +01:00
TW
a13504c6d5
Merge pull request #7903 from ThomasWaldmann/update-changes-1.2
update CHANGES (1.2-maint)
2023-11-04 18:05:03 +01:00
Thomas Waldmann
d9a0deb227
update CHANGES 2023-11-03 18:43:22 +01:00
TW
686714c366
Merge pull request #7896 from ThomasWaldmann/fix-shadow-index-1.2
fix shadow index update for double-put (1.2-maint)
2023-11-03 14:42:57 +01:00
TW
55ee4e2d28
Merge pull request #7897 from ThomasWaldmann/check-fixes-shadow-index-1.2
check --repair fixes shadow_index (1.2-maint)
2023-11-03 14:42:39 +01:00
TW
cf5c61644b
Merge pull request #7901 from ThomasWaldmann/update-docs-1.2
Update docs (1.2-maint)
2023-11-03 14:35:02 +01:00
Thomas Waldmann
6b928dac93
docs: not only attack/unsafe, can also be a fs issue, fixes #7853 2023-11-01 18:04:24 +01:00
Thomas Waldmann
da4fcc5a66
docs: point to CVE-2023-36811 upgrade steps from borg 1.1 to 1.2 upgrade steps, fixes #7899
also: use 1.2.6 to refer to the fixed version

1.2.5 had issues and was superseded by 1.2.6 just 1 day later,
so we do not need to talk about that.

Also, the docs point out that:
"""
Below, if we speak of borg 1.2.6, we mean a borg version >= 1.2.6 **or** a
borg version that has the relevant security patches for this vulnerability applied
(could be also an older version in that case).
"""

So, it now just talks about "1.2.6" at the relevant places.
2023-11-01 18:04:22 +01:00
Thomas Waldmann
136e3ed1d6
docs: upgrade steps needed for all kinds of repos, fixes #7813
Repos with encryption=none of course can not do real authentication (because there is no secret key material to work with).

But the code always works the same way and such repos also use (and expect) TAMs, so the instructions should be followed in any case.
2023-11-01 18:04:20 +01:00
Thomas Waldmann
a19ebe5ecc
docs: consequences of borg check, fixes #7816 2023-11-01 17:18:32 +01:00
Thomas Waldmann
a7809429b3
check --repair: recreate shadow index, see #6687
before this fix, borg check --repair just created an
empty shadow index, which can lead to incomplete
entries if entries are added later.

and such incomplete (but present) entries can lead to
compact_segments() resurrecting old PUTs by accidentally
dropping related DELs.
2023-10-29 01:12:15 +02:00
Thomas Waldmann
48feb28e11
check --repair: test if shadow index is recreated
still failing here, because it is not.
2023-10-29 01:01:17 +02:00
Thomas Waldmann
8a8837e255
shadow index updates: simplify and more comments
no functional change here.
2023-10-28 17:36:10 +02:00
Thomas Waldmann
b21ed3c658
update shadow index when doing a double-put, fixes #5661
this fixes the test added in previous commit (avoids
that the PUT reappears after index rebuild).
2023-10-28 17:17:47 +02:00
Thomas Waldmann
8e6449f28e
test the shadowing-by-double-put behaviour, see #5661
the new test is currently failing due to a bug in the
repository code.
2023-10-28 17:13:13 +02:00
TW
c35cddeb7e
Merge pull request #7892 from ThomasWaldmann/ci-timeout-1.2
CI: increase timeout to 90min
2023-10-28 01:25:33 +02:00
Thomas Waldmann
dff29627dc
CI: increase timeout to 90min
esp. the macOS CI jobs are sometimes rather slow,
so 40min were not enough.
2023-10-27 22:30:52 +02:00
TW
b83525cd4c
Merge pull request #7891 from ThomasWaldmann/sort-by-aliases-1.2
--sort-by: support "archive" as alias of "name", fixes #7873 (1.2-maint)
2023-10-27 22:27:59 +02:00
TW
fa7a6d7095
Merge pull request #7890 from ThomasWaldmann/doc-updates-1.2
doc updates (1.2-maint)
2023-10-27 22:25:59 +02:00
Thomas Waldmann
0e3773d8c7
--sort-by: support "archive" as alias of "name", fixes #7873 2023-10-27 20:46:03 +02:00
TW
75bc62e2ae
Merge pull request #7889 from ThomasWaldmann/udev-uuid-1.2
automated-local.rst: use GPT UUID for consistent udev rule (1.2-maint)
2023-10-27 20:33:57 +02:00
Thomas Waldmann
05cec8b3b0
docs: OS X -> macOS 2023-10-27 20:31:26 +02:00
Thomas Waldmann
7a4d53c2f5
docs: update macOS hint about full disk access 2023-10-27 20:28:57 +02:00
Thomas Waldmann
661e5cccd3
docs: minor fixes/update to notes 2023-10-27 20:27:51 +02:00
Thomas Waldmann
d13b5d5557
docs: remove info about borg 1.0 files per dir 2023-10-27 20:26:27 +02:00
Thomas Waldmann
e0f80812a5
docs: no signature upload on pypi any more
but we upload it on github releases,
so people can check it.
2023-10-27 20:25:29 +02:00
Thomas Waldmann
7640973d6b
docs: CI only on github actions now 2023-10-27 20:23:00 +02:00
azrdev
69d71d99bf
automated-local.rst: Partition table UUID match works for MBR too
not only GPT
2023-10-27 20:15:05 +02:00
azrdev
b61a565fbc
automated-local.rst: use GPT UUID for consistent udev rule 2023-10-27 20:14:50 +02:00
TW
4a8f8bf789
Merge pull request #7886 from ThomasWaldmann/fix-inv-pattern-errorhandling-1.2
Fix arg parsing error handling (1.2-maint)
2023-10-27 20:09:36 +02:00
Thomas Waldmann
5bfa417546
fix rc and msg if arg parsing throws an exception, fixes #7885
get_args() exception handling before this fix only dealt with
subclasses of "Error", but we have to expect other exceptions
there, too.

In any case, if we have some fatal exception here, we must
terminate with rc 2.

ArgumentTypeError: emit a short error message - usually this is
a user error, invoking borg in a wrong way.

Other exceptions: full info and traceback.
2023-10-25 12:06:27 +02:00
Thomas Waldmann
1bd015cdb5
fix invalid pattern argument error msg 2023-10-25 11:06:37 +02:00
Johannes Lade
d482251a3e
Clarify borg prune -a option description (#7871)
Clarify borg prune -a option description.

The -a option for borg prune accepts only glob pattern (i.e. sh:)
but not the actual prefix sh: which can be confusing especially for
people who don't actually know what glob pattern is.
2023-10-14 22:00:19 +02:00
TW
e2ea9b6547
Merge pull request #7864 from ThomasWaldmann/remove-bountysource-badge-1.2
remove bountysource badge (1.2-maint)
2023-10-10 21:01:56 +02:00
Thomas Waldmann
b8d950d097
remove bountysource badge 2023-10-10 20:32:11 +02:00
TW
bc553b1258
Merge pull request #7857 from ThomasWaldmann/misc-updates-1.2
misc. updates (1.2-maint)
2023-10-09 20:57:11 +02:00
Felix Schwarz
90de901ff4
replace "datetime.utcfromtimestamp" with custom helper to avoid deprecation warnings when using Python 3.12 2023-10-09 20:23:10 +02:00
Thomas Waldmann
f72adc9e61
vagrant: use generic/debian9 box, fixes #7579
the debian/stretch64 was broken and never fixed.
2023-10-08 21:53:32 +02:00
Thomas Waldmann
37c3177e90
update development.lock.txt
there was some breakage with py312, so better
use current tooling.
2023-10-08 21:42:04 +02:00
Thomas Waldmann
d6ad508a29
github CI: test on py312 (w/o -dev) 2023-10-08 00:20:31 +02:00
Thomas Waldmann
3c4b1090a6
vagrant: install py312 via pyenv 2023-10-08 00:15:39 +02:00
Thomas Waldmann
9df5e6c139
allow setuptools_scm >= 8 again
8.0.4 got a fix, so we can allow it again.
2023-10-08 00:10:36 +02:00
TW
8c267e5c3c
Merge pull request #7850 from ThomasWaldmann/allow-msgpack107-1.2
allow msgpack 1.0.7 (1.2-maint)
2023-09-28 15:36:54 +02:00
Thomas Waldmann
39761ebadc
allow msgpack 1.0.7 2023-09-28 14:26:48 +02:00
TW
e936d53a66
Merge pull request #7845 from ThomasWaldmann/update-changes-1.2
update CHANGES
2023-09-26 00:03:10 +02:00
Thomas Waldmann
5195fb2dcf
update CHANGES 2023-09-25 17:07:28 +02:00
TW
c9c495db0a
Merge pull request #7839 from ThomasWaldmann/traceback-for-tam-exceptions-1.2
activate tracebacks for TAM exceptions
2023-09-25 16:53:22 +02:00
TW
4188e03ffc
Merge pull request #7844 from ThomasWaldmann/py312-1.2
support python 3.12 (1.2-maint)
2023-09-25 16:45:04 +02:00
Thomas Waldmann
1a24c2fa43
avoid tarfile deprecation warning for py312 2023-09-25 15:36:43 +02:00
Thomas Waldmann
8f820d1f32
add wheel to build-system requirements 2023-09-25 15:34:44 +02:00
Thomas Waldmann
906962b631
setup.py: declare python 3.12 support 2023-09-25 15:33:02 +02:00
Thomas Waldmann
ce274aa11c
test on python 3.12-dev 2023-09-25 15:29:30 +02:00
TW
47e65d9c00
Merge pull request #7842 from ThomasWaldmann/offline-docs2-1.2
offline docs: remove epub, pdf. only build htlmzip.
2023-09-25 15:15:10 +02:00
Thomas Waldmann
377d02c4b2
offline docs: remove epub, pdf. only build htlmzip.
something is broken with these, build fails.
2023-09-25 15:14:26 +02:00
TW
20f9953293
Merge pull request #7841 from ThomasWaldmann/offline-docs-1.2
readthedocs: also build offline docs, fixes #7835 (1.2-maint)
2023-09-25 14:47:52 +02:00
TW
6170ab7d34
Merge pull request #7840 from ThomasWaldmann/allow-msgpack106-1.2
Allow msgpack 1.0.6 (1.2-maint)
2023-09-25 14:47:28 +02:00
Thomas Waldmann
da2b885179
readthedocs: also build offline docs, fixes #7835 2023-09-25 14:24:13 +02:00
Thomas Waldmann
ed87e45bab
use setuptools_scm < 8 for now
https://github.com/pypa/setuptools_scm/issues/938
2023-09-25 14:14:51 +02:00
Thomas Waldmann
93b93abc18
allow msgpack 1.0.6 2023-09-25 14:10:32 +02:00
Thomas Waldmann
6dbfbd6a19
activate tracebacks for TAM exceptions 2023-09-25 11:01:38 +02:00
TW
0c198160f8
Merge pull request #7821 from ThomasWaldmann/vagrant-updates-1.2
vagrant: add VM with debian bookworm
2023-09-12 22:07:41 +02:00
Thomas Waldmann
3d367b0fd3
vagrant: add VM with debian bookworm
this also brings OpenSSL 3.0.x.
2023-09-12 18:41:38 +02:00
TW
83028c0b89
Merge pull request #7820 from ThomasWaldmann/remove-twine-1.2
remove twine from requirements
2023-09-12 17:37:34 +02:00
Thomas Waldmann
1407a2b2fb
remove twine from requirements
twine is only needed at release time, no need
for all developers or all test runs to install
this.

also, some requirement of twine needs a rust
compiler, so if there is no rust compiler,
automated runs will abort due to that.
2023-09-12 17:05:02 +02:00
TW
a0069d4b45
Merge pull request #7801 from ThomasWaldmann/fix-upgrade-docs-1.2
docs: minor fix to CVE-2023-36811 related upgrade instructions
2023-09-02 15:53:06 +02:00
Thomas Waldmann
97b8eb2104
docs: minor fix to CVE-2023-36811 related upgrade instructions
while the main issue in the code has been fixed since 1.2.5,
let's better refer to 1.2.6, which has fixes in upgrade docs and code.
2023-09-02 15:47:13 +02:00
TW
ee6a8e2ddf
Merge pull request #7798 from ThomasWaldmann/check-improve-TAM-logging-1.2
check: improve logging for TAM issues, fixes #7797
2023-09-01 22:07:59 +02:00
Thomas Waldmann
7fd91f4bb8
check: improve logging for TAM issues, fixes #7797 2023-09-01 15:35:04 +02:00
TW
65d75c167a
Merge pull request #7792 from ThomasWaldmann/rel126
Release 1.2.6
2023-08-31 23:37:46 +02:00
Thomas Waldmann
98dea3e876
requirements: remove cython restrictions 2023-08-31 01:03:34 +02:00
Thomas Waldmann
c133303243
update CHANGES, incl. upgrade instructions 2023-08-31 01:02:44 +02:00
Thomas Waldmann
d05d02f238
implement BORG_WORKAROUNDS=ignore_invalid_archive_tam, see #7791 2023-08-31 00:36:04 +02:00
TW
7ab28487ce
Merge pull request #7790 from ThomasWaldmann/fix-changelog-markup-1.2
fix changelog markup
2023-08-30 18:41:31 +02:00
Thomas Waldmann
447d0df1bb
fix changelog markup 2023-08-30 18:36:42 +02:00
TW
f7a93b30fa
Merge pull request #7788 from ThomasWaldmann/fix-cve-docs-1.2
fix CVE timeline
2023-08-30 14:41:05 +02:00
Thomas Waldmann
ee33c22443
fix CVE timeline 2023-08-30 14:39:41 +02:00
TW
c8b9d72bdb
Merge pull request from GHSA-8fjr-hghr-4m99
Release 1.2.5 incl. archives TAM security fix
2023-08-30 14:18:17 +02:00
Thomas Waldmann
509a5fd71c
build_usage / build_man 2023-08-30 03:49:47 +02:00
Thomas Waldmann
ed1ab84cc7
update CHANGES 2023-08-30 03:47:35 +02:00
Thomas Waldmann
9e63abb679
document vulnerability, repo upgrade procedure 2023-08-30 02:52:34 +02:00
Thomas Waldmann
5e0632a3d0
add tests for archive TAMs, upgrade 2023-08-30 02:52:32 +02:00
Thomas Waldmann
d78ed697ae
rebuild_refcounts: keep archive ID, if possible
rebuild_refcounts verifies and recreates the TAM.
Now it re-uses the salt, so that the archive ID does not change
just because of a new salt if the archive has still the same data.
2023-08-30 02:52:27 +02:00
Thomas Waldmann
85b173d3d1
TAM msgs: be more specific: archives vs. manifest 2023-08-30 02:52:23 +02:00
Thomas Waldmann
7d0d11b979
upgrade: allow enable/disable manifest TAM for unencrypted repos
Recent borg wrote TAM authenticated **archives**
even for unencrypted repos (encryption "none"),
so we also do that for the manifest.

It's kind of fake as there is no secret key involved then,
but it simplifies the code.
2023-08-30 02:52:21 +02:00
Thomas Waldmann
19a7809fe8
upgrade --archives-tam: make sure all archives are TAM authenticated
borg check (rebuild_manifest and rebuild_refcounts) drops archives without TAM,
so let's just always add the TAM.

for unencrypted repos (encryption=none) the TAM is insecure,
but without encryption and authentication, there is no expectation
of security anyway.
2023-08-30 02:52:17 +02:00
Thomas Waldmann
75518d945c
list: support {tam} placeholder. check archive TAM.
list: shows either "verified" or "none", depending on
whether a TAM auth tag could be verified or was
missing (old archives from borg < 1.0.9).

when loading an archive, we now try to verify the archive
TAM, but we do not require it. people might still have
old archives in their repos and we want to be able to
list such repos without fatal exceptions.
2023-08-30 02:52:15 +02:00
Thomas Waldmann
155d8ee23b
cache sync: check archive TAM 2023-08-30 02:52:13 +02:00
Thomas Waldmann
7da8738513
check: rebuild_refcounts verify and recreate TAM
This part of the archive checker recreates the Archive
items (always, just in case some missing chunks needed
repairing).

When loading the Archive item, we now verify the TAM.
When saving the (potentially modified) Archive item,
we now (re-)generate the TAM.

Archives without a valid TAM are dropped rather than TAM-authenticated
when saving them. There shouldn't be any archives without a valid TAM:

- borg writes an archive TAM since long (1.0.9)
- users are expected to TAM-authenticate archives created
  by older borg when upgrading to borg 1.2.5.

Also:

Archive.set_meta: TAM-authenticate new archive

This is also used by Archive.rename and .recreate.
2023-08-30 02:51:52 +02:00
Thomas Waldmann
1fd94bd38f
check: rebuild_manifest must verify archive TAM 2023-08-29 21:59:04 +02:00
TW
8ae06199ef
Merge pull request #7784 from ThomasWaldmann/vagrant-updates-1.2
Vagrant updates (1.2-maint)
2023-08-29 20:49:13 +02:00
Thomas Waldmann
de51c67085
vagrant: fix netbsd pkgsrc
9.0_current stopped working, let's use 9.3.
2023-08-29 19:45:39 +02:00
Thomas Waldmann
055fb76bd8
vagrant / binary build: use python 3.9.18 2023-08-29 19:44:30 +02:00
TW
9133cf5f36
Merge pull request #7783 from ThomasWaldmann/rel-prep-1.2
build_man / build_usage
2023-08-29 18:50:04 +02:00
Thomas Waldmann
62ca4f666b
build_man / build_usage 2023-08-29 18:48:41 +02:00
TW
a034febe55
Merge pull request #7782 from ThomasWaldmann/update-changes-1.2
update CHANGES
2023-08-29 18:34:10 +02:00
Thomas Waldmann
7f07f81e39
update CHANGES 2023-08-29 18:24:56 +02:00
TW
186b3d1319
Merge pull request #7781 from ThomasWaldmann/cy029-1.2
require cython <3 for now
2023-08-29 16:15:33 +02:00
Thomas Waldmann
f8673a379c
require cython <3 for now
also in requirements.d/development.txt.
2023-08-29 16:09:08 +02:00
TW
844ca6b61e
Merge pull request #7772 from ThomasWaldmann/cython029-1.2
use cython 0.29 (1.2-maint)
2023-08-26 14:44:54 +02:00
Thomas Waldmann
37a813f7f8
stay on latest Cython 0.29 (0.29.36) for borg 1.2.x
master branch tests Cython 3 now.
1.2-maint branch may or may not upgrade to build with Cython 3 later.
2023-08-26 14:18:23 +02:00
TW
0493695b6c
Merge pull request #7769 from ThomasWaldmann/docs-fix-rcreate-1.2
docs: fix borg init command in environment.rst.inc
2023-08-24 12:04:38 +02:00
Thomas Waldmann
276781081b
docs: fix borg init command in environment.rst.inc
It mentioned borg rcreate due to a bad backport from master.
Must be borg init in borg 1.2.x.
2023-08-24 11:49:17 +02:00
TW
f6e20fb07c
Merge pull request #7751 from ThomasWaldmann/fix-unreadable-parent-of-root-fixup-1.2
remove unused "flags_root" open flags
2023-07-30 01:18:40 +02:00
Thomas Waldmann
de7e7e2a95
remove unused "flags_root" open flags 2023-07-29 23:42:36 +02:00
TW
ef52d13608
Merge pull request #7749 from ThomasWaldmann/fix-unreadable-parent-of-root-1.2
do not try to read parent dir of recursion root (1.2-maint)
2023-07-29 23:38:28 +02:00
Thomas Waldmann
ed7a410084
create: do not try to read parent dir of recursion root, fixes #7746 2023-07-29 23:04:44 +02:00
Thomas Waldmann
453d35fa47
add a test for unreadable parent dir, see #7746 2023-07-29 22:48:13 +02:00
TW
a3f4adf899
Merge pull request #7732 from ThomasWaldmann/update-docs-1.2
update docs 1.2
2023-07-23 15:08:31 +02:00
Thomas Waldmann
dedbd38844
1.1.x upgrade notes: more precise borg upgrade instructions, fixes #3396 2023-07-22 18:08:35 +02:00
Thomas Waldmann
b419b6ad03
build_man / build_usage 2023-07-20 18:57:22 +02:00
Thomas Waldmann
65a2fe8502
update CHANGES 2023-07-20 18:54:55 +02:00
TW
aa913cda83
Merge pull request #7731 from ThomasWaldmann/authenticated_no_key-fix-1.2
bugfix: skip TAM check with BORG_WORKAROUNDS=authenticated_no_key
2023-07-20 18:34:05 +02:00
Thomas Waldmann
104cc196fc
bugfix: skip TAM check with BORG_WORKAROUNDS=authenticated_no_key
This is an emergency workaround for authenticated repos
if the user has lost the borg key.

We can't compute the TAM key without the borg key, so just
skip all the TAM stuff.
2023-07-20 18:02:58 +02:00
TW
b067aeadef
Merge pull request #7723 from PhrozenByte/docs-check-rewrite-1.2
Backport: Docs: Rewrite `borg check` docs
2023-07-11 00:49:20 +02:00
Daniel Rudolf
c6a6161c60
Docs: Rewrite borg check docs
This commit is a backport of the following commits to the `1.2-maint` branch:

    commit 9edbf4e931
    Author: Daniel Rudolf

        Docs: Rewrite `borg check` docs

    commit 9d59146de4
    Author: Daniel Rudolf

        Docs: Remove technical description from `borg check` docs

    commit a661da13ee
    Author: Daniel Rudolf

        Docs: Improve explanation of `borg check --max-duration`'s side effects

    commit 2647673dc8
    Author: Daniel Rudolf

        Docs: Improve `borg check` docs
2023-07-10 23:03:47 +02:00
TW
4721a35863
Merge pull request #7702 from ThomasWaldmann/authenticated-no-key-1.2
BORG_WORKAROUNDS=authenticated_no_key, fixes #7700
2023-07-07 01:02:41 +02:00
TW
c79e970b78
Merge pull request #7717 from FelixSchwarz/borg12-py312
add `utcnow()` helper function to avoid `datetime.utcnow()`
2023-07-06 23:45:58 +02:00
Felix Schwarz
98f547f278 add utcnow() helper function to avoid datetime.utcnow()
`datetime.utcnow()` is deprecated since Python 3.12. This causes additional lines of
output and thus breaks the test suite. I was not sure if all borg internals are
ready to deal with timezone-aware datetime instances so tried to keep the changes
minimal.
2023-07-06 21:44:09 +02:00
TW
e5cc2e16e3
Merge pull request #7709 from TimWolla/backport-doc-keep-within
Backport: Improve the documentation for `--keep-within`
2023-07-04 14:11:55 +02:00
Tim Düsterhus
b58c6ce3b1 Improve the documentation for --keep-within
Move the explanation below the general explanation of the `--keep-*` option
behavior rephrase the last sentence to make it clear that it works like the
other options that were explained in the previous paragraph.

Resolves #7687

(cherry picked from commit a6f452a050)
2023-07-04 09:16:39 +02:00
TW
dfa04eece6
Merge pull request #7704 from ThomasWaldmann/remove-coala-1.2
remove coala (outdated)
2023-07-03 19:11:27 +02:00
Thomas Waldmann
ae7fd9b101
remove coala (outdated)
last coala release (0.11.0) is now over 6y old.

when using pip install coala, a ton of stuff gets installed (expected)
and a part of that downgrades some stuff we use to outdated, incompatible
versions.

when trying to run coala with python 3.11, it just crashes because the
last release was made for py35/py36 (as seen in their setup.py).

a lot of PRs and tickets pile up at the coala project on github,
but noone is maintaining it.
2023-07-03 18:40:52 +02:00
Thomas Waldmann
8ac7178ab9
BORG_WORKAROUNDS=authenticated_no_key to extract from authenticated repos without key, fixes #7700 2023-07-03 15:38:21 +02:00
TW
6b0dc53f11
Merge pull request #7693 from ThomasWaldmann/docs-1.2
docs updates (1.2-maint)
2023-07-01 15:07:04 +02:00
Thomas Waldmann
d01852c100
update CHANGES 2023-07-01 14:49:28 +02:00
Thomas Waldmann
6d9e8e5483
docs: move upgrade notes to own section, see #7546 2023-07-01 14:43:44 +02:00
Thomas Waldmann
55af769b71
mount -olocal: how to show mount in finder's sidebar, fixes #5321 2023-07-01 14:43:35 +02:00
TW
98cea7516b
Merge pull request #7691 from ThomasWaldmann/macfuse-volname-1.2
mount: make up volname if not given (macOS), fixes #7690
2023-07-01 14:41:14 +02:00
TW
230065f52b
Merge pull request #7694 from ThomasWaldmann/fix-4110-1.2
extract: fix false warning about pattern never matching, fixes #4110
2023-07-01 14:40:24 +02:00
Thomas Waldmann
f5f5311e2b
extract: fix false warning about pattern never matching, fixes #4110 2023-07-01 02:05:58 +02:00
Thomas Waldmann
7c82969761
mount: make up volname if not given (macOS), fixes #7690
macFUSE supports a volname mount option to give what
finder displays on desktop / in directory list.

if the user did not specify it, we make something up,
because otherwise it would be "macFUSE Volume 0 (Python)".
2023-06-30 22:10:32 +02:00
TW
de53164931
Merge pull request #7689 from ThomasWaldmann/diff-surrogate-escape-1.2
diff: remove surrogates before output, fixes #7535
2023-06-30 17:52:26 +02:00
Thomas Waldmann
c587e88830
diff: remove surrogates before output, fixes #7535 2023-06-30 17:10:56 +02:00
TW
a0bc7b9434
Merge pull request #7683 from ThomasWaldmann/fix-repo-reopen-1.2
tests: fix repo reopen 1.2 (backport from master)
2023-06-28 00:24:41 +02:00
Thomas Waldmann
fbf287f825
RepositoryTestCaseBase: remove need for "with" after reopen()
setUp enters the context manager, so let's .reopen() leave it.
then create a fresh Repository instance in self.repository and
enter the context manager again. tearDown then will leave that.
2023-06-27 22:43:00 +02:00
Thomas Waldmann
0ac07b7a3f
RepositoryTestCaseBase: call __exit__
As we call __enter__ in setUp,
let's call __exit__ in tearDown.
2023-06-27 22:34:11 +02:00
Thomas Waldmann
83b2b5cb6c
fix RepositoryTestCaseBase.reopen method
"if self.repository" did not work as expected:
- Repository has a __len__ method, so the boolean evaluation was calling that.
- self.repository is also not set to None anywhere.
2023-06-27 22:33:57 +02:00
TW
0947e9fb22
Merge pull request #7680 from ThomasWaldmann/improve-key-sanity-check-1.2
keyfile: improve key sanity check, fixes #7561
2023-06-27 22:32:30 +02:00
TW
edc9a0843a
Merge pull request #7682 from ThomasWaldmann/test-cosmetics-1.2
tests: avoid long ids in pytest output
2023-06-27 22:30:16 +02:00
Thomas Waldmann
81588989fe
tests: avoid long ids in pytest output
sometimes the automatically computed IDs are just too long,
so rather give IDs directly or avoid them otherwise.
2023-06-27 21:50:51 +02:00
Thomas Waldmann
a5801b9971
keyfile: improve key sanity check, fixes #7561
check key file structure, make sure the binary key
is not way too short (or zero) length.

if key file looks strange, emit warnings.
2023-06-27 21:39:43 +02:00
TW
1da5beacb3
Merge pull request #7678 from ThomasWaldmann/fix-crash-files-cache-size-1.2
--files-cache=size: fix crash, fixes #7658
2023-06-27 21:36:49 +02:00
TW
c7d5fff200
Merge pull request #7679 from ThomasWaldmann/pypi-no-upload-signature-1.2
do not upload gpg signature to pypi, fixes #7649
2023-06-27 21:36:05 +02:00
TW
f6805f3850
Merge pull request #7681 from ThomasWaldmann/fix-list-pattern-docs-1.2
list: fix --pattern examples, fixes #7611
2023-06-27 21:35:41 +02:00
Thomas Waldmann
893530fdac
list: fix --pattern examples, fixes #7611
- pattern needs to start with + - !
- first match wins
- the default is to list everything, thus a 2nd pattern
  is needed to exclude everything not matched by 1st pattern.
2023-06-27 21:00:05 +02:00
Thomas Waldmann
de643c211b
do not upload gpg signature to pypi, fixes #7649 2023-06-27 18:45:41 +02:00
Thomas Waldmann
45aa88dbec
--files-cache=size: fix crash, fixes #7658 2023-06-27 18:40:48 +02:00
TW
f73eb5c6c2
Merge pull request #7644 from eoli3n/1.2-maint
Backport of improvements in patterns help
2023-06-11 17:10:47 +02:00
eoli3n
91547e9844 improve patterns help: declarative includes sample 2023-06-11 11:14:24 +02:00
eoli3n
099f23032e improve patterns help: added pattern prefixes 2023-06-11 11:12:49 +02:00
eoli3n
3e8b0da8be improve patterns help: define a pattern style 2023-06-11 11:09:41 +02:00
eoli3n
952d778bc1 Improve patterns help 2023-06-11 11:08:31 +02:00
TW
c5d579be39
Merge pull request #7628 from ThomasWaldmann/fix-chunksize-distrib-test-1.2
fix test_buzhash_chunksize_distribution
2023-06-06 11:25:11 +02:00
Thomas Waldmann
796d8e2d13
fix test_buzhash_chunksize_distribution
the last chunk can be smaller than 2**min_exp.
2023-06-06 10:46:53 +02:00
TW
742d0df294
Merge pull request #7613 from ThomasWaldmann/1.2-clear-empty-dirs-typo
fix typo
2023-05-29 15:22:15 +02:00
Thomas Waldmann
e711df20e2
fix typo 2023-05-29 14:56:47 +02:00
TW
0bfbd8d8fc
Merge pull request #7595 from nain-F49FF806/1.2-clear-empty-dirs
clear empty directories at end of compact process, fixes #6823
2023-05-27 11:04:13 +02:00
nain
aac55b1ad2 Add function to clear empty directories at end of compact process.
Compact moves data to new segments, and then removes the old segments.
When enough segments are moved, directories holding the now cleared segments
may thus become empty.

With this commit any empty directories are cleared after segments compacting.
Fixes #6823
2023-05-27 04:41:50 -04:00
TW
912dc81a2d
Merge pull request #7606 from nain-F49FF806/data-scandir-unify
unify scanning and listing of segment dirs, files and apply good practices
2023-05-27 10:31:36 +02:00
nain
edb5e749f5 Move value bounds of segment (index) into constants module and use them instead 2023-05-27 02:33:53 -04:00
nain
3f2da1bba9 Simplify generator functions and make get_segment_dirs inputs consistent with get_segment_files
+ get_segment_dirs explicitly takes data_dir for clarity and future flexibility
+ removed multiple cases for one general purpose generator expression
2023-05-26 02:42:13 -04:00
nain
c9f35a16e9 unify scanning and listing of segment dirs / segment files and apply good practices
+ os.scandir instead of os.listdir
  Improved speed and added flexibility with attributes (name,path,is_dir(),is_file())
+ use is_dir / is_file to make sure  we're reading only dirs / files respectively
+ Filtering to particular start, end index range built in
+ Have seperate generators to avoid unnecessary less_than / greater_than checking for every dir/file when not required

Resolves #7597
2023-05-25 11:55:16 -04:00
TW
53bedfb63b
Merge pull request #7589 from ThomasWaldmann/chunker-params-1.2
relax chunker params validation, tests (1.2-maint)
2023-05-19 19:19:04 +02:00
Thomas Waldmann
5cc4e3af6a
tests: only warn about "invalid" chunker params, fixes #7590
we previously allowed some weird chunker params, so we just warn
about them instead of rejecting them.

e.g. one could use super small chunk sizes. borg can do that,
but you'll end up with a huge amount of chunks and very large
hash tables (RAM usage) to manage them.

also, one can violate the min <= mask <= max chunker param condition
as in #7590 and it will somehow work, but will likely not dedup as good
as when not violating that.

borg2 **will** reject such strange chunker params, see #7586 for
some ideas how to "fix" your repos.
2023-05-19 18:05:26 +02:00
Thomas Waldmann
965e8a957f
tests: check buzhash chunksize distribution, see #7586 2023-05-19 18:05:20 +02:00
TW
ce50796b1f
Merge pull request #7568 from elandorr/1.2-maint
incl./excl. options, path-from-stdin exclusiveness
2023-05-15 21:48:29 +02:00
elandorr
8e41831f4c
Update archiver.py 2023-05-15 11:39:10 +00:00
elandorr
dedd58969c
mention paths-from-stdin's exclusiveness 2023-05-14 20:28:52 +00:00
elandorr
4047076e70
include/exclude options 2023-05-14 20:21:41 +00:00
TW
823f0fb9e0
Merge pull request #7564 from elandorr/1.2-maint
doc markup fixes
2023-05-14 18:58:42 +02:00
elandorr
6b38207aeb
markup fix + note about MAX_DATA_SIZE 2023-05-14 07:57:12 +00:00
elandorr
f1bd5da8c9
escape 2023-05-14 07:50:27 +00:00
TW
dbc142a32a
Merge pull request #7549 from sashadev-sky/fix-progress-msg-width-1.2
ProgressIndicatorPercent: fix space computation for wide chars, fixes #3027
2023-05-08 19:46:17 +02:00
Thomas Waldmann
21a9458848 ProgressIndicatorPercent: fix space computation for wide chars, fixes #3027
needs to use swidth() in case there are wide chars (like CJK)
in the left part of the msg (e.g. an archive name).

(cherry picked from commit 3dd14f4855)
2023-05-08 12:44:05 -04:00
TW
2181103c3f
Merge pull request #7550 from sashadev-sky/fix-argparse-errors-1.2
Fix argparse error messages
2023-05-08 15:39:11 +02:00
TW
1d4a7803dd
Merge pull request #7547 from sashadev-sky/issue-7476-1.2
Added pre-commit for linting purposes. Fixes #7476
2023-05-08 15:28:51 +02:00
Thomas Waldmann
3e9668ecbc fix CompressionSpec validator and tests
(cherry picked from commit 0b40e038ad)
2023-05-07 21:03:56 -04:00
Thomas Waldmann
de199c23ab fix SortBySpec validator
(cherry picked from commit 05bf29f504)
2023-05-07 21:01:10 -04:00
Thomas Waldmann
7707ea538c fix FilesCacheMode validator
(cherry picked from commit 0f923c8c4a)
2023-05-07 21:00:20 -04:00
Thomas Waldmann
067e36bccc fix ChunkerParams validator and tests
(cherry picked from commit 6d38530ff1)
2023-05-07 20:59:17 -04:00
Sasha Boginsky
5b5e9282e3 Remove black formatting from cherry-pick 2023-05-07 18:52:42 -04:00
TW
d1ddd57eaf
Merge pull request #7548 from sashadev-sky/option-x-help-1.2
improve --one-file-system help /docs
2023-05-06 20:35:59 +02:00
Thomas Waldmann
49b58bfbab --one-file-system: add macOS apfs notes, fixes #4876
(cherry picked from commit b7adee65bd)
2023-05-06 03:00:08 -04:00
Thomas Waldmann
8cbaaf6113 improve --one-file-system help string, fixes #5618
(cherry picked from commit 6ca1ed9716)
2023-05-06 02:59:14 -04:00
Michael Deyaso
172b03ef4d Changed black rev in pre-commit yaml. Fixes #7476
(cherry picked from commit 20a4c960ec)
2023-05-05 23:51:14 -04:00
Michael Deyaso
9e7b20660b Installed and configured pre-commit to lint and format code. Fixes #7476
(cherry picked from commit 98d1c65b40)
2023-05-05 23:51:09 -04:00
TW
0067077f7a
Merge pull request #7480 from ThomasWaldmann/update-codeql-1.2
codeql action: upgrade to v2 (1.2-maint)
2023-03-27 20:07:28 +02:00
Thomas Waldmann
54d8636a2d
codeql action: upgrade to v2 2023-03-27 16:28:19 +02:00
TW
7d649faea1
Merge pull request #7466 from ThomasWaldmann/rel124
release 1.2.4
2023-03-23 23:24:34 +01:00
Thomas Waldmann
35d76f9a64
build_man 2023-03-23 22:11:46 +01:00
Thomas Waldmann
0d14f3b36f
build_usage 2023-03-23 22:11:45 +01:00
Thomas Waldmann
b81b1abdeb
it's 2023! 2023-03-23 22:11:44 +01:00
Thomas Waldmann
73ee704afa
security: 1.1.x is EOL, please upgrade to 1.2.x.
That means I won't make new 1.1.x releases.

In case there would be a major security or other issue,

I might still make a fix commit to the 1.1-maint branch,
where dist package maintainers or other interested
parties could find it.
2023-03-23 22:11:42 +01:00
Thomas Waldmann
391e05a6c6
change log: set release date, remove outdated stuff 2023-03-23 22:11:41 +01:00
Thomas Waldmann
af16e19933
update CHANGES 2023-03-23 22:10:22 +01:00
TW
05bfed50c3
Merge pull request #7471 from Michael-Girma/bug/issue-7470
Resolved mode bug and added sleep clause for darwin systems. Fixes #7470
2023-03-23 21:29:56 +01:00
Michael Deyaso
ea08161fe8 Resolved mode bug and added sleep clause for darwin systems. Fixes #7470 2023-03-23 21:39:55 +03:00
TW
de2f894bcc
Merge pull request #7464 from ThomasWaldmann/docs-borg-key-file-1.2
BORG_KEY_FILE: clarify docs, fixes #7444
2023-03-22 22:33:42 +01:00
TW
4c230a52e6
Merge pull request #7465 from dotdoom/1.2-maint-ignorezeros
Add --ignore-zeros flag to import-tar
2023-03-22 22:31:37 +01:00
Artem Sheremet
3b7c0605af Add --ignore-zeros flag to import-tar
Fixes #7432.

Backport of #7460.
2023-03-22 18:59:58 +01:00
Thomas Waldmann
e6b8e03e19
BORG_KEY_FILE: clarify docs, fixes #7444 2023-03-22 18:52:58 +01:00
TW
671c66361d
Merge pull request #7456 from ThomasWaldmann/update-changes-1.2
update CHANGES (1.2-maint)
2023-03-20 23:00:03 +01:00
Thomas Waldmann
3cffbbd3af
update CHANGES 2023-03-20 22:10:49 +01:00
TW
2ab678ca93
Merge pull request #7414 from Michael-Girma/backport/1.2-maint-7248
Show ctime and mtime on borg diff, fixes #7248 (Backport of #7335)
2023-03-20 14:14:30 +01:00
Michael Deyaso
19bb27741d bugfix: Fixes path related bug seen when addressing deferred items. 2023-03-20 07:28:59 +03:00
TW
62080a5737
Merge pull request #7441 from ThomasWaldmann/vagrant-updates2-1.2
Vagrant updates2 (1.2-maint)
2023-03-13 09:56:20 +01:00
Thomas Waldmann
cfd6f035ff
vagrant: use pythons working on freebsd
pyenv could not install py38, thus using the fbsd system py38.

removed py38 from pyenv completely.
2023-03-13 04:05:24 +01:00
Thomas Waldmann
96dff54655
vagrant: freebsd: kldload fusefs 2023-03-13 00:56:09 +01:00
TW
6354e4ada4
Merge pull request #7435 from ThomasWaldmann/freebsd-xattr-fixes-1.2
xattrs: fix namespace processing on FreeBSD, fixes #6997
2023-03-13 00:54:13 +01:00
Thomas Waldmann
bd299f1ff3
xattrs: fix namespace processing on FreeBSD, fixes #6997 2023-03-12 23:35:52 +01:00
TW
f623742709
Merge pull request #7439 from ThomasWaldmann/vagrant-updates-1.2
Vagrant updates (1.2-maint)
2023-03-12 23:34:22 +01:00
Thomas Waldmann
e3f887414b
vagrant: pyenv: also install python 3.11.1 for testing 2023-03-12 23:07:11 +01:00
Thomas Waldmann
96a8a98d97
vagrant: pyenv: use python 3.10.1, 3.10.0 build is broken on freebsd 2023-03-12 23:06:57 +01:00
Thomas Waldmann
fc0c594ff6
vagrant: local freebsd 12.1 box -> generic/freebsd13 box
Building in the 12.1 box stopped working, thus replaced it
with the same box as we use in master.
2023-03-12 23:06:50 +01:00
TW
0a61c7b767
Merge pull request #7428 from ThomasWaldmann/update-changes-1.2
update CHANGES (1.2-maint)
2023-03-11 19:17:52 +01:00
TW
c9190fe867
Merge pull request #7434 from ThomasWaldmann/remove-os-directory-1.2
docs: remove OS directory from install docs
2023-03-11 19:15:58 +01:00
Thomas Waldmann
f2825a96d2
docs: remove OS directory from install docs
- links did not work that way
- each OS has its own headline and can be discovered easily without
  that directory
2023-03-11 18:52:58 +01:00
TW
019a999364
Merge pull request #7429 from abebeos/1.2-maint
docs: installation: add link to OS dependencies
2023-03-11 01:16:36 +01:00
abebeos
9e464edb7c docs: installation: add link to OS dependencies 2023-03-10 22:39:30 +00:00
Thomas Waldmann
cd35e22d06
update CHANGES 2023-03-10 22:46:10 +01:00
TW
134583a7bf
Merge pull request #7412 from ThomasWaldmann/hardlink-master-bug-1.2
set .hardlink_master for hardlinkable items, fixes #7175
2023-03-10 19:49:12 +01:00
TW
7643f39901
Merge pull request #7419 from ThomasWaldmann/msgpack105-1.2
allow msgpack 1.0.5 also
2023-03-09 22:20:22 +01:00
Thomas Waldmann
2842463f21
allow msgpack 1.0.5 also 2023-03-09 17:58:57 +01:00
Michael Deyaso
6c042d7192 Show ctime and mtime on borg diff. Fixes #7248
---

- Added assert_line_exists helper in BaseTestCase
- JSON strings in diff output are now sorted alphabetically
- Modified diff test cases to confirm to new output format
- Added a test case to test ctime and mtime inclusion
- Mode, ctime & mtime are now only displayed on diff if --content-only flag is used
2023-03-07 10:54:29 +03:00
Thomas Waldmann
843c12cbea
set .hardlink_master for hardlinkable items, fixes #7175
before, we only set this for regular files, but we better also set this
for block/char devices and fifos also, so we have it for all item types
borg 1.x considers "hardlinkable".

this is important for sequential processing of items in an archive:
if we encounter a hardlinkable item and .source is not set (that
would make it a hardlink slave), it could be a hardlink master or not:

- hardlink_master == False  # this item is not part of a hl group
- hardlink_master == True  # this item is a hardlink master

This will also be important when items are converted to borg2.
2023-03-05 19:20:22 +01:00
TW
d44cf3482e
Merge pull request #7402 from ThomasWaldmann/unicode-filenames-docs-1.2
update FAQ about locale/unicode issues, fixes #6999
2023-03-05 17:48:55 +01:00
TW
d5e4f3f8cf
Merge pull request #7404 from ThomasWaldmann/mount-docs-1.2
docs: improve mount options rendering, fixes #7359
2023-03-05 17:48:01 +01:00
TW
ca1fea37a6
Merge pull request #7410 from snsmac/backport/autocompressortests
"auto" compressor tests: don't assume a specific size (backport to 1.2-maint)
2023-03-05 17:22:45 +01:00
TW
831c9d0c40
Merge pull request #7408 from snsmac/backport/hashindex
hashindex bugfix and refactoring (backport to 1.2-maint)
2023-03-05 15:29:50 +01:00
Thomas Waldmann
8cf313900a "auto" compressor tests: do not assume zlib is better than lz4, fixes #7363
while that might be true for many cases, we can not assume it is
always true, as proven by the failing test on S390.
2023-03-05 11:05:47 +01:00
Thomas Waldmann
a7ce1db529 add num_entries assertion 2023-03-05 11:01:44 +01:00
Thomas Waldmann
f1d68fe4b3 hashindex: simplify size_idx function
Thanks to @jdchristensen for the code.
2023-03-05 11:01:44 +01:00
Thomas Waldmann
d57fafadad Simplify full HT scan assertion 2023-03-05 11:01:44 +01:00
Thomas Waldmann
ec32413b5e hashindex: always have at least 1 empty bucket
avoid rounding / integer conversion issues bringing this down to 0.
2023-03-05 11:01:44 +01:00
Thomas Waldmann
241eaec413 implement ht idx wrap around less strangely, add comment 2023-03-05 11:01:44 +01:00
Thomas Waldmann
51189e1383 if HT is full with entries and tombstones: give up/fail early 2023-03-05 11:01:44 +01:00
Thomas Waldmann
32519617b6 more comments for hashindex_lookup 2023-03-05 11:01:44 +01:00
Thomas Waldmann
3a44894aca bugfix: do not resize hashindex with wrong num_empty
otherwise we would lose the decrement operation on num_empty.
2023-03-05 11:01:44 +01:00
Thomas Waldmann
ecf5ad43ed hashindex: simplify assert 2023-03-05 11:01:44 +01:00
Thomas Waldmann
b2117bfd4f _hashindex: easier to understand code, dubious loops removed, asserts
hashindex_index returns the perfect hashtable index, but does not
check what's in the bucket there, so we had these loops afterwards
to search for an empty or deleted bucket.

problem: if the HT were completely filled with no empty and no deleted
buckets, that loop would never end. due to our HT resizing, it can
never happen, but still not pretty.

when using hashindex_lookup (as also used some lines above), the code
is easier to understand, because (after we resized the HT), we freshly
create the same situation as after the first call of that function:
- return value < 0, because we (still) can not find the key
- start_idx will point to an empty bucket

Thus, we do not need the problematic loops we had there.

Modified the checks to make sure we really have an empty or deleted
bucket before overwriting it with data.

Added some additional asserts to make sure the code behaves.
2023-03-05 11:01:44 +01:00
TW
cef5b446ac
Merge pull request #7411 from ThomasWaldmann/debug-id-hash-command-1.2
debug id-hash: implement file content id-hash computation, see #7406
2023-03-04 22:33:20 +01:00
TW
42fb72c022
Merge pull request #7409 from snsmac/backport/hashtablestress
Add hashtable stress test (backport to 1.2-maint)
2023-03-04 22:14:47 +01:00
Thomas Waldmann
eb8ccd22d4
debug id-hash: implement file content id-hash computation, see #7406 2023-03-04 21:47:14 +01:00
snsmac
c339d2e9e2 Update hashtable stress test to work with borg < 2 where NSIndex has 2-tuples as values 2023-03-04 21:41:31 +01:00
TW
086a4237ca
Merge pull request #7407 from ThomasWaldmann/fix-debug-cmds-1.2
fix borg debug get-obj/put-obj (1.2-maint)
2023-03-04 21:21:09 +01:00
Thomas Waldmann
356ba3cc79
debug put-obj: id must be given on commandline, fixes #7290
this is an incompatible change:

before:
borg debug put-obj :: path1 path2 ...
(and borg computed all IDs automatically) (*)

after:
borg debug put-obj :: id path
(id must be given)

(*) the code just using sha256(data) was outdated and incorrect anyway.

also: fix error handling in get-obj.
2023-03-04 20:25:45 +01:00
Thomas Waldmann
8fe980c94e "auto" compressor tests: don't assume a specific size, fixes #7363
The tests assumed a specific compressed results size, which
is bad, because it might vary depending on the zlib implementation.

Now the "auto" compressor tests just check if it is the same size
as when unconditionally using the zlib compressor.
2023-03-04 20:19:08 +01:00
Thomas Waldmann
b7d70f2064 add comment about how to provoke more collisions 2023-03-04 20:09:58 +01:00
Thomas Waldmann
b33fea7718 add hashtable stress tests
Using NSIndex (repo index) HashIndex, but they all are very similar.
2023-03-04 20:09:50 +01:00
Thomas Waldmann
d739f29657
docs: improve mount options rendering, fixes #7359 2023-03-04 17:08:15 +01:00
Thomas Waldmann
e8573193e4
update FAQ about locale/unicode issues, fixes #6999 2023-03-04 16:32:48 +01:00
TW
6e8c58c125
Merge pull request #7395 from helmutg/reproducible-docs-1.2
Make timestamps in manual pages reproducible
2023-03-01 09:20:20 +01:00
Vagrant Cascadian
a5c9231e88 Make timestamps in manual pages reproducible
Refer to https://reproducible-builds.org/docs/source-date-epoch/ for
documentation on SOURCE_DATE_EPOCH.

Bug-Debian: https://bugs.debian.org/1029807
Signed-off-by: Helmut Grohne <helmut@subdivi.de>

(cherry picked from commit 98352cf667)
2023-02-28 13:38:45 +01:00
TW
a7a80ffe90
Merge pull request #7382 from ThomasWaldmann/rtd-config-1.2
add .readthedocs.yaml
2023-02-25 18:51:51 +01:00
Thomas Waldmann
fd6e76e6a4
add .readthedocs.yaml
same as in master branch
2023-02-25 18:42:49 +01:00
TW
836bd0339d
Merge pull request #7361 from voegelas/1.2-maint-fedora
Installation: Update Fedora in distribution list
2023-02-17 18:58:50 +01:00
Andreas Vögele
007b73ac67 Installation: Update Fedora in distribution list
Fixes #7357
2023-02-17 14:45:17 +01:00
TW
1dce595d8f
Merge pull request #7338 from ThomasWaldmann/timestamp-comparisons-1.2
relaxed timestamp comparisons (1.2)
2023-02-11 00:19:08 +01:00
TW
e41466dbb3
Merge pull request #7337 from ThomasWaldmann/fix-recreate-rechunkify-1.2
recreate without --chunker-params shall not rechunk (1.2)
2023-02-10 18:37:11 +01:00
Thomas Waldmann
6bf818a2a1
tests: use same_ts_ns for all timestamp comparisons 2023-02-10 18:36:10 +01:00
Thomas Waldmann
b3da30e6d4
same_ts_ns: add a timestamp comparison function
also: HAVE_UTIMES means 1us resolution (*)

(*) at least as far as the utimes() call is concerned.

Whether there are other limitations has to be seen.
2023-02-10 17:58:46 +01:00
Thomas Waldmann
cd23d810d3
recreate: --chunker-params must default to None, fixes #7337
before the fix, it triggered rechunking if an archive
was created with non-default chunker params.

but it only should rechunk if borg recreate is invoked with explicitly giving --chunker-params=....
2023-02-10 14:12:08 +01:00
Thomas Waldmann
dbe1c98cb3
tests: recreate without --chunker-params shall not rechunk 2023-02-10 14:01:04 +01:00
TW
5ccfaa7a45
Merge pull request #7299 from ThomasWaldmann/test-dir-mtime-1.2
add test for extracted directory mtime
2023-01-28 00:59:59 +01:00
Thomas Waldmann
b472768b57
more directory timestamp tests 2023-01-24 15:58:30 +01:00
Thomas Waldmann
2291ab755d
add test for extracted directory mtime 2023-01-24 15:22:01 +01:00
TW
48713ebff6
Merge pull request #7265 from ThomasWaldmann/fix-locking-1.2
Fix locking (1.2-maint)
2023-01-19 18:15:28 +01:00
TW
dbba9cbc53
Merge pull request #7268 from ThomasWaldmann/recreate-with-target-1.2
recreate: when --target is given, do not detect "nothing to do"
2023-01-16 17:22:50 +01:00
Thomas Waldmann
c43140686b
recreate: when --target is given, do not detect "nothing to do"
use case:

borg recreate -a src --target dst can be used to make a copy
of an archive inside the same repository, see #7254.
2023-01-14 19:28:57 +01:00
Thomas Waldmann
16eb38e20a
fix host, pid, tid order
using "differenthost" (== not the current hostname) makes
the process_alive check always return True (to play safe,
because in can not check for processes on other hosts).
2023-01-13 22:36:50 +01:00
Thomas Waldmann
91104674e7
use os.replace not os.rename 2023-01-13 22:32:11 +01:00
Thomas Waldmann
804867d3ad
bugfix: thread id must be parsed as hex from lock file name 2023-01-13 22:30:28 +01:00
TW
1dcaa74788
Merge pull request #7252 from puetzk/test_size_on_disk_accurate-flush-1.2
[1.2-maint] Fix test_size_on_disk_accurate for large st_blksize, fixes #7250
2023-01-12 20:52:48 +01:00
Kevin Puetz
fe3775cf80 Fix test_size_on_disk_accurate for large st_blksize, fixes #7250
python's io.BufferedWriter sizes its buffer based on st_blksize.
If the write fits in this buffer, then it's possible the data from
idx.write() has not been flushed through to ,the underlying filesystem,
and getsize(fileno()) sees a too-short (or even empty) file.

Also, getsize is only documented as accepting path-like objects;
passing a fileno seems to work only because the implementation
blindly forwards everything through to os.stat without checking.

Passing unopened_tempfile avoids all three problems
- on windows, it doesn't rely on re-opening NamedTemporaryFile
  (the issue which led to 8ddfd94f09)
- we're following the documented API of getsize(path-like)
- the file is closed (thus flushed) inside idx.write, before getsize()
2023-01-11 19:19:43 -06:00
TW
2336c4b5a6
Merge pull request #7256 from ThomasWaldmann/docs-libb2-1.2
remove BORG_LIBB2_PREFIX (not used any more)
2023-01-10 14:24:38 +01:00
Thomas Waldmann
47e0f9bcb0
remove BORG_LIBB2_PREFIX (not used any more)
the code now uses hashlib.blake2b from python stdlib.
2023-01-10 14:09:28 +01:00
TW
1ac19b034b
Merge pull request #7242 from ThomasWaldmann/upgrade-cython-1.2
upgrade Cython to 0.29.33
2023-01-06 22:04:18 +01:00
TW
32b5f44bbb
Merge pull request #7235 from ThomasWaldmann/macos-resourcefork-mtime-1.2
extract: fix mtime when ResourceFork xattr is set (macOS specific)
2023-01-06 21:41:29 +01:00
Thomas Waldmann
497eca0faf
upgrade Cython to 0.29.33 2023-01-06 21:39:22 +01:00
Thomas Waldmann
b96781b9dd
macOS: fix mtime timestamp extraction if ResourceFork xattr is present, fixes #7234
setting the timestamps after xattrs helps for correct mtime,
but atime is still broken in this case.
2022-12-30 00:08:06 +01:00
Thomas Waldmann
c095e2ef61
macOS: test correct timestamp extraction if ResourceFork xattr is present, see #7234 2022-12-30 00:08:04 +01:00
TW
4ca090bb8c
Merge pull request #7229 from ThomasWaldmann/update-requirements-1.2
update development.lock.txt
2022-12-27 20:31:28 +01:00
Thomas Waldmann
3837e0233d
update development.lock.txt
including a setuptools security fix, see #7227

also:
- cosmetic change in development.txt to have same order
- removed exclusion of broken Cython release (outdated since long)
2022-12-27 19:32:20 +01:00
TW
06716a7971
Merge pull request #7224 from ThomasWaldmann/rel123
release 1.2.3
2022-12-24 23:25:57 +01:00
Thomas Waldmann
ae8b0eb3e4
avoid git complaining about dubious ownership
this lead to breakage of setuptools_scm, it could not
determine the borg version under fakeroot due to this
git / ownership issue.
2022-12-24 18:15:49 +01:00
Thomas Waldmann
795a553675
build_man 2022-12-24 18:09:33 +01:00
Thomas Waldmann
ec49d60d1f
build_usage 2022-12-24 18:09:32 +01:00
Thomas Waldmann
e4cbd28bdd
update CHANGES 2022-12-24 18:09:30 +01:00
Thomas Waldmann
ffd6d51b2c
fix xattr tests
while fixing #6988, some strings were changed, but the tests not adapted:

a758fda089
2022-12-24 18:09:28 +01:00
TW
ab0f0d24fd
Merge pull request #7223 from ThomasWaldmann/fix-docs-prefix-1.2
Fix docs / tests concerning deprecated --prefix (1.2-maint)
2022-12-24 15:10:56 +01:00
Thomas Waldmann
90a937e1ed
remove deprecated --prefix from docs, fixes #7109
also:

- rather mention --glob-archives
- rather test --glob-archives
2022-12-24 14:44:05 +01:00
TW
2f78e545e0
Merge pull request #7222 from ThomasWaldmann/vagrant-updates
Vagrant updates
2022-12-24 04:40:08 +01:00
Thomas Waldmann
aa2c2a4e34
vagrant: use python 3.9.16 for the binary build 2022-12-24 02:24:35 +01:00
Thomas Waldmann
5a442743f5
vagrant: use the openbsd 7.1 box
openbsd 6.9 was removed from the ftp servers and
the vagrant box stopped working. so we now use the
same box as in master branch.
2022-12-24 02:21:50 +01:00
TW
5704c4d887
Merge pull request #7215 from ThomasWaldmann/github-actions-updates-1.2
GitHub actions updates (1.2-maint)
2022-12-17 21:39:07 +01:00
TW
28bf1db2c8
Merge pull request #7216 from ThomasWaldmann/fix-ci-1.2
fix github CI (1.2-maint)
2022-12-17 21:38:05 +01:00
Thomas Waldmann
96d36e32cb
github CI: set PKG_CONFIG_PATH again
strange: on macOS, the globally set PKG_CONFIG_PATH was overwritten,
thus the borg build did not find openssl any more. setting it here
locally again works around the issue.
2022-12-17 20:27:49 +01:00
Thomas Waldmann
dd8e5487e3
github CI: prepend to PKG_CONFIG_PATH 2022-12-17 20:27:39 +01:00
Thomas Waldmann
0849ef25de
github CI: use actions/cache@v3 2022-12-17 20:02:52 +01:00
Thomas Waldmann
b69721ebe0
no fail fast, just checking... 2022-12-17 18:48:41 +01:00
Thomas Waldmann
fe1c89e5ba
github CI: use actions/setup-python@v4
should fix the node12 deprecation warning.
2022-12-17 18:33:26 +01:00
Thomas Waldmann
bb1c132bbc
github CI: use actions/checkout@v3
should fix the node12 deprecation warning.
2022-12-17 18:33:12 +01:00
Thomas Waldmann
73097c8162
github CI: use ubuntu-20.04 (not -latest)
affects only the lint job, everything else used 20.04 already.
2022-12-17 18:33:06 +01:00
TW
d61f5eba63
Merge pull request #7214 from ThomasWaldmann/update-changes-1.2
update CHANGES (1.2-maint)
2022-12-17 18:13:31 +01:00
Thomas Waldmann
9c8ac57399
update CHANGES 2022-12-17 18:04:03 +01:00
TW
2aae879c49
Merge pull request #7210 from ThomasWaldmann/list-directories-dry-run-1.2
create: --list --dry-run output for directories, fixes #7209
2022-12-15 17:50:46 +01:00
Thomas Waldmann
dca6792850
create: --list --dry-run output for directories, fixes #7209
Without the status being set no output was generated in
dry-run mode, confusing users about whether borg would back
up directories (in non-dry-run mode).

- == item not backed up just because of dry-run mode
x == item excluded
2022-12-15 17:26:36 +01:00
TW
6d5c4a48b3
Merge pull request #7201 from ThomasWaldmann/fix-macos-ci-1.2
fix tox4 issue on macOS CI (1.2-maint)
2022-12-10 20:52:29 +01:00
Thomas Waldmann
e66d8c399b
fix tox4 passenv issue, fixes #7199
also: have a setting to disable fail-fast, in case something breaks again.
2022-12-10 19:55:28 +01:00
TW
79b6c985a1
Merge pull request #7169 from ThomasWaldmann/update-twine-upload-1.2
twine: use repo name instead of url
2022-11-27 01:25:39 +01:00
Thomas Waldmann
3984a7e3da
twine: use repo name instead of url 2022-11-27 01:24:25 +01:00
TW
d4cd911d46
Merge pull request #7150 from ThomasWaldmann/fix-nfiles-1.2
Fix nfiles 1.2
2022-11-20 20:30:25 +01:00
TW
889c8778a1
Merge pull request #7149 from ThomasWaldmann/py311-1.2
update python 3.9 and 3.11
2022-11-20 18:48:25 +01:00
Thomas Waldmann
f6419ee28b
archive.save(): always use metadata from stats, fixes #7072
e.g. nfiles, size, etc.

fixes:
- checkpoint archives did not have this metadata yet
- borg import-tar did not have this metadata yet
2022-11-20 18:33:53 +01:00
Thomas Waldmann
822a23da92
github CI: use python 3.11 (not -dev) 2022-11-20 17:58:43 +01:00
Thomas Waldmann
d623b47da9
vagrant: use python 3.9.15 for tests/binary build 2022-11-20 17:57:16 +01:00
TW
c233a964f2
Merge pull request #7147 from ThomasWaldmann/fix-repository-tests-1.2
Fix repository tests 1.2
2022-11-19 17:06:07 +01:00
Rayyan Ansari
d0b09dfc95
testsuite: repository: skip some tests for RemoteRepository 2022-11-19 14:30:41 +01:00
Rayyan Ansari
82f6adf8e0
file_integrity.py: make sure file_fd is always closed on exit 2022-11-19 14:30:16 +01:00
Rayyan Ansari
9cff9d96fa
testsuite: repository: close fd before deleting segment
See last commit.
2022-11-19 14:28:14 +01:00
Rayyan Ansari
05505de807
repository: cleanup(): close segment before unlinking
On Windows, trying to delete a file that is already open raises an exception.

Docs:
https://docs.python.org/3/library/os.html#os.remove
2022-11-19 14:25:01 +01:00
Rayyan Ansari
6a97e936ac
repository: use os.replace instead of os.rename
On Windows, os.rename raises an exception if the destination file already exists, unlike os.replace which replaces the destination file.

Docs:
https://docs.python.org/3/library/os.html#os.rename
https://docs.python.org/3/library/os.html#os.replace
2022-11-19 14:22:35 +01:00
TW
97261dbb22
Merge pull request #7135 from ThomasWaldmann/remove-py37-compat-code-1.2
remove python < 3.7 compatibility code
2022-11-07 09:04:37 +01:00
Thomas Waldmann
f1a355f3d9
remove python < 3.7 compatibility code
not supported any more in master and 1.2-maint branches.
2022-11-06 18:25:03 +01:00
TW
fff56edd8a
Merge pull request #7130 from ThomasWaldmann/fix-6070-1.2
improve/clarify strange test code, fixes #6070
2022-11-05 02:15:25 +01:00
TW
2ae41fd9e6
Merge pull request #7128 from ThomasWaldmann/fix-root-paths-1.2
fix args.paths related argparsing, fixes #6994
2022-11-05 01:12:45 +01:00
Thomas Waldmann
25d6649bcd improve/clarify strange test code, fixes #6070 2022-11-05 00:51:44 +01:00
Thomas Waldmann
d57ed9dd98 fix args.paths related argparsing, fixes #6994
argparse: the default action is "store" and that overwrote an already
existing list in args.paths (e.g. from --pattern="R someroot") when it
started to process the positional PATH args.

with "extend" it now extends the existing args.paths with the list of
positional PATH arguments (which can be 0..N elements long, nargs="*").

note: "extend" is new since python 3.8, thus this can only be backported
to 1.2-maint, but not to 1.1-maint.
2022-11-05 00:30:46 +01:00
TW
01b921dea4
Merge pull request #7124 from ThomasWaldmann/hashindex-test-win-1.2
Fix test_size_on_disk_accurate on Windows
2022-11-04 21:12:58 +01:00
Thomas Waldmann
8ddfd94f09 Fix test_size_on_disk_accurate on Windows
Pass the python file object / fd instead of the file path.

On Windows, a tempfile cannot be opened again, unlike on Unix systems.
See https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile
2022-11-04 20:28:09 +01:00
TW
3d1f11b2e2
Merge pull request #7106 from RayyanAnsari/msys2-ci-backport
Use MSYS2 for Windows CI [backport]
2022-10-28 19:11:39 +02:00
Rayyan Ansari
e8dd5c449e
Add new Windows build scripts and CI with GitHub and MSYS2 [backport]
Fixes #7105
2022-10-27 16:56:08 +01:00
Rayyan Ansari
4b27ab2fbd
Remove old Windows scripts and Appveyor CI [backport] 2022-10-27 16:33:02 +01:00
nyuszika7h
84f4c12752
tar_filter: recognize .tar.zst as zstd (backport) (#7095)
tar_filter: recognize .tar.zst as zstd

Backported from #7093
2022-10-22 13:41:11 +02:00
TW
0989cb4040
Merge pull request #7082 from ThomasWaldmann/fix-chunker-params-comparison
Fix chunker params comparison
2022-10-11 20:29:32 +02:00
Thomas Waldmann
3200190cdb diff: more precise warning msgs for different chunker params
if we know both archives' chunker params, use "are different" not "might be".
also do not recommend to enforce it using --same-chunker-params in this case.
2022-10-11 19:44:11 +02:00
Thomas Waldmann
651bef450d recreate: normalize chunker params before comparing them, see #7079
borg < 1.2 did not have the chunker name as first element in the tuple,
but it always was buzhash, because there was no other chunker.
2022-10-10 22:41:39 +02:00
Thomas Waldmann
a6207370a9 diff: normalize chunker params before comparing them, fixes #7079
borg < 1.2 did not have the chunker name as first element in the tuple,
but it always was buzhash, because there was no other chunker.
2022-10-10 22:27:12 +02:00
TW
773f3bff77
Merge pull request #7057 from ThomasWaldmann/fix-recreate-fixed-chunker-1.2
get_chunker: fix missing sparse=False argument, fixes #7056
2022-09-27 22:36:03 +02:00
Thomas Waldmann
875c94a20d get_chunker: fix missing sparse=False argument, fixes #7056 2022-09-27 21:45:51 +02:00
Thomas Waldmann
2f6197df0c add test for recreate with "fixed" chunker 2022-09-27 21:45:51 +02:00
Emmanuel Tanimowo
f49133da04
update automating backups script (#7039)
update "automating backups" script: remove last backslash, use --glob-archives
2022-09-21 00:54:38 +02:00
TW
44b4791e98
Merge pull request #7035 from ThomasWaldmann/fix-7034-1.2
check: fix uninitialised variable if repo is completely empty, fixes #7034
2022-09-17 20:51:48 +02:00
Thomas Waldmann
4f4be2631a check: fix uninitialised variable if repo is completely empty, fixes #7034 2022-09-17 20:29:34 +02:00
TW
9fe7339a39
Merge pull request #7024 from ThomasWaldmann/compat-setuptoolsscm4-1.2
do not use version_tuple placeholder in setuptools_scm template
2022-09-17 13:26:55 +02:00
Thomas Waldmann
3404346419 do not use version_tuple placeholder in setuptools_scm template
that would require setuptools_scm>=5.0.0 but some dists do not have that yet.
also, we do not use the version_tuple from _version.py, so it is not required
anyway.
2022-09-13 21:25:35 +02:00
TW
1b3cbe2461
Merge pull request #6990 from ThomasWaldmann/more-fine-grained-extended-stat-1.2
xattrs / extended stat: improve exception handling (1.2-maint)
2022-09-05 16:06:10 +02:00
Thomas Waldmann
3bd3600875 cosmetic: add missing blank to xattr test skip reason 2022-08-24 14:19:53 +02:00
Thomas Waldmann
a758fda089 xattrs: improve error handling, fixes #6988
looks like we can not rely on listxattr only returning
valid, acceptable names for getxattr.

so getxattr can still fail with EINVAL.

also:

- do not raise an exception if getting a single
xattr fails, rather emit a warning and continue
processing the remaining xattrs (and also the whole
file). we already had that for EPERM (and similar
for ENOATTR), just do it for all errors.

- _check, when it raises OSError, gives us a nice
exception object, use it.

- more helpful error msgs, try not to lose error information
2022-08-24 12:03:51 +02:00
Thomas Waldmann
b5d43506d3 extended stat: more fine grained exception handling
see #6988: it was unclear where exactly the error came from (flags, xattrs or ACLs getting?).
2022-08-23 21:56:31 +02:00
TW
9bfe210948
Merge pull request #6980 from ThomasWaldmann/rel122
release 1.2.2
2022-08-20 21:04:12 +02:00
Thomas Waldmann
101a06234f netbsd vagrant box: py310, remove some outdated fixes
seems like that stuff got fixed in 9.3.
2022-08-20 16:52:31 +02:00
Thomas Waldmann
e87c54a0a1 update CHANGES 2022-08-20 15:38:10 +02:00
Thomas Waldmann
bbad73502b requirements.lock.txt: upgrade Cython and tox 2022-08-20 15:38:10 +02:00
Thomas Waldmann
92ca260fd8 build_usage ; build_man 2022-08-20 15:38:10 +02:00
Thomas Waldmann
b024379904 fix sphinx warnings 2022-08-20 15:38:10 +02:00
TW
4e2cc02e86
Merge pull request #6967 from ThomasWaldmann/fix-versionpy-format-1.2
_version.py: remove trailing blank, add LF at EOF
2022-08-15 15:17:56 +02:00
TW
ec389edc83
Merge pull request #6944 from ThomasWaldmann/fix-ctrl-c-remote-repo-1.2
ctrl-c must not kill important subprocesses, fixes #6912
2022-08-13 23:23:50 +02:00
Thomas Waldmann
6799405012 _version.py: remove trailing blank, add LF at EOF 2022-08-13 20:35:03 +02:00
Thomas Waldmann
7a31978c55 ctrl-c must not kill other subprocesses, fixes #6912
There are some other places with subprocesses:

- borg create --content-from-command
- borg create --paths-from-command
- (de)compression filter process of import-tar / export-tar
2022-08-06 12:48:54 +02:00
Thomas Waldmann
5d83d5f153 ctrl-c must not kill the ssh subprocess, fixes #6912 2022-08-06 12:29:10 +02:00
TW
e215525339
Merge pull request #6943 from ThomasWaldmann/update-changes-1.2
update CHANGES
2022-08-06 11:37:07 +02:00
Thomas Waldmann
c4e552a1e5 update CHANGES 2022-08-06 10:41:58 +02:00
TW
fa8d8ecd73
Merge pull request #6918 from ThomasWaldmann/compaction-debugging-1.2
repository: add debug logging for issue #6687
2022-08-06 10:27:23 +02:00
TW
52cba940ea
Merge pull request #6936 from ThomasWaldmann/mkstemp_mode-1.2
use a custom mkstemp with mode support, fixes #6933, fixes #6400
2022-08-05 13:04:24 +02:00
TW
28bc76a916
Merge pull request #6937 from ThomasWaldmann/fix-warnings-1.2
Fix warnings (1.2-maint)
2022-08-04 18:23:34 +02:00
Thomas Waldmann
69f4898460 make setuptools happy, fixes #6874
work around setuptools puking about:

          ############################
          # Package would be ignored #
          ############################
          Python recognizes 'borg.cache_sync' as an importable package,
          but it is not listed in the `packages` configuration of setuptools.

          'borg.cache_sync' has been automatically added to the distribution only
          because it may contain data files, but this behavior is likely to change
          in future versions of setuptools (and therefore is considered deprecated).

          Please make sure that 'borg.cache_sync' is included as a package by using
          the `packages` configuration field or the proper discovery methods
          (for example by using `find_namespace_packages(...)`/`find_namespace:`
          instead of `find_packages(...)`/`find:`).

          You can read more about "package discovery" and "data files" on setuptools
          documentation page.
2022-08-04 15:50:05 +02:00
Thomas Waldmann
b3b5602ac2 _chunker.c: fix warnings on macOS
macOS does not have POSIX_FADV_DONTNEED, thus some variables are not
needed.
2022-08-04 14:51:06 +02:00
Thomas Waldmann
b0eee13124 use a custom mkstemp with mode support, fixes #6933, fixes #6400
hopefully this is the final fix.

after first fixing of #6400 (by using os.umask after mkstemp), there
was a new problem that chmod was not supported on some fs.

even after fixing that, there were other issues, see the ACLs issue
documented in #6933.

the root cause of all this is tempfile.mkstemp internally using a
very secure, but hardcoded and for our use case problematic mode
of 0o600.

mkstemp_mode (mosty copy&paste from python stdlib tempfile module +
"black" formatting applied) supports giving the mode via the api,
that is the only change needed.

slightly dirty due to the _xxx imports from tempfile, but hopefully
this will be supported in some future python version.
2022-08-04 14:22:56 +02:00
Thomas Waldmann
e5b6670bc6 repository: add debug logging for issue #6687
i suspect that compact_segments wrongly drops some DEL tags.

this could make already deleted chunks re-appear, leading to:
- suddenly more repo index entries than previously (check, repo part)
- suddenly orphaned chunks appearing (check, archives part)

if this is the case, the issue is harmless, but annoying/confusing.

to fix the issue, i need the complete log line "dropping DEL for id X".
the id X it mentions is one of the chunk ids borg check complains about.
2022-07-31 19:05:54 +02:00
TW
4b54cfef45
Merge pull request #6914 from ThomasWaldmann/update-changes-1.2
update CHANGES
2022-07-30 18:32:58 +02:00
Thomas Waldmann
fe27be9f3e update CHANGES 2022-07-30 17:57:57 +02:00
TW
ade2241163
Merge pull request #6911 from horazont/docs/internal-details-1.2
docs(1.2): provide more details on object layout
2022-07-30 17:43:27 +02:00
Jonas Schäfer
bd89fb717e docs: provide more details on object layout
While writing my own out-of-band decoder, I had a hard time figuring out
how to unpack the manifest. From the description, I was only able to
read that the manifest is msgpack'd, but I had not been able to figure
out that it's also going through the same encryption+compression logic
as all other things do.

This should make it a little clearer and provide the necessary
information to understand how the compression works.
2022-07-30 17:32:36 +02:00
TW
01f87c6ca1
Merge pull request #6887 from ThomasWaldmann/prune-checkpointing-1.2
prune/delete --checkpoint-interval=1800 and ctrl-c/SIGINT support, fixes #6284
2022-07-30 16:54:50 +02:00
TW
5e291ff5e1
Merge pull request #6905 from ThomasWaldmann/fix-flags-formatting-1.2
list: fix {flags:<WIDTH>} formatting, fixes #6081
2022-07-30 15:34:19 +02:00
TW
78ae0114d4
Merge pull request #6909 from ThomasWaldmann/update-changes-1.2
update CHANGES
2022-07-30 15:30:48 +02:00
TW
32616111e0
Merge pull request #6901 from ThomasWaldmann/fix-5719-1.2
check: try harder to create the key, fixes #5719
2022-07-30 15:30:32 +02:00
Thomas Waldmann
e7bd9e8442 update CHANGES 2022-07-29 11:48:18 +02:00
Thomas Waldmann
e81f6f34cd list: fix {flags:<WIDTH>} formatting, fixes #6081
item.bsdflags is either not present or an int, thus we default to 0 (== no flags) if not present.
2022-07-29 10:09:00 +02:00
Thomas Waldmann
ea4c47ec7a check: try harder to create the key, fixes #5719
the old code did just 1 attempt to detect the repo decryption key.
if the first chunkid we got from the chunks hashtable iterator was accidentally
the id of the chunk we intentionally corrupted in test_delete_double_force,
setup of the key failed and that made the test crash.

in practice, this could of course also happen if chunks are corrupted, thus
we now do many retries with other chunks before giving up.

error handling was improved: do not return None (instead of a key), it just
leads to weird crashes elsewhere, but fail early with IntegrityError and a
reasonable error msg.

rename method to make_key to avoid confusion with borg.crypto.key.identify_key.
2022-07-29 09:08:03 +02:00
Thomas Waldmann
f8e33cfdf1 prune/delete --checkpoint-interval=1800 and ctrl-c/SIGINT support, fixes #6284
manifest, repo and cache are committed every checkpoint interval.

also, when ctrl-c is pressed, finish deleting the current archive, commit and then terminate.
2022-07-28 19:15:23 +02:00
TW
3d94c595b0
Merge pull request #6896 from ThomasWaldmann/ci-macos-1.2
CI: test on macOS 12 without fuse / fuse tests
2022-07-28 00:09:59 +02:00
Thomas Waldmann
9fb9508f4b CI: test on macOS 12 without fuse / fuse tests
too troublesome on github CI due to kernel extensions needed by macFUSE.
2022-07-27 23:10:10 +02:00
remyabel2
c56025000b
docs: add info on man page installation (#6894) 2022-07-27 13:46:48 +02:00
TW
4c3da429fb
Merge pull request #6890 from ThomasWaldmann/archive-progress-json-docs-1.2
docs: update archive_progress json description about "finished"
2022-07-27 12:46:59 +02:00
Thomas Waldmann
404fe33a8d docs: update archive_progress json description about "finished", see #6570 2022-07-25 13:06:06 +02:00
TW
a4a2530a29
Merge pull request #6877 from LocutusOfBorg/fix-template-1.2
Fix pyproject.toml to create a fixed _version.py file, compatible wi…
2022-07-19 16:41:41 +02:00
Gianfranco Costamagna
ad8555e921 Fix pyproject.toml to create a fixed _version.py file, compatible with both old and new setuptools_scm version (see: #6875) 2022-07-18 19:51:04 +02:00
TW
907764e018
Merge pull request #6850 from ThomasWaldmann/deprecated-prefix-option-1.2
deprecate --prefix, use -a / --glob-archives, see #6806
2022-07-09 16:57:58 +02:00
Thomas Waldmann
c265370cff deprecate --prefix, use -a / --glob-archives, see #6806 2022-07-09 16:12:34 +02:00
TW
a8c556b5e9
Merge pull request #6843 from ThomasWaldmann/expect-1.2
Automate asciinema screencasts (1.2-maint)
2022-07-07 00:36:59 +02:00
TW
8a42d88120 Merge pull request #6197 from hexagonrecursion/expect
Automate asciinema screencasts
2022-07-07 00:01:28 +02:00
TW
1fba67efee
Merge pull request #6824 from ThomasWaldmann/fix-progress-percent-docs-1.2
docs: json progress_percent: some values are optional, fixes #4074
2022-07-02 20:21:36 +02:00
Thomas Waldmann
bfae252593 docs: json progress_percent: some values are optional, fixes #4074
in the finished == true message, these are missing:
- message
- current / total
- info

This is to be somewhat consistent with #6683 by only providing a
minimal set of values for the finished case.

The finished messages is primarily intended for cleanup purposes,
e.g. clearing the progress display.
2022-07-01 14:31:23 +02:00
TW
9c463dc46b
Merge pull request #6816 from ThomasWaldmann/fix-hashindex-compact-1.2
hashindex_compact: fix eval order (check idx before use), fixes #5899
2022-06-30 20:57:38 +02:00
Thomas Waldmann
3f517b019a hashindex_compact: fix eval order (check idx before use), fixes #5899
also: fix "off by one" comment
2022-06-29 18:58:26 +02:00
TW
25c9826456
Merge pull request #6814 from fantasya-pbem/docs/5960_FAQ-quota-size_1.2-maint
[DOCS] #5960 - FAQ: Full quota / full disk
2022-06-29 18:55:36 +02:00
Thalian
6990aca7ac [DOCS] #5960 - FAQ: Full quota / full disk
Backport from master.
2022-06-29 17:56:23 +02:00
TW
0cac871b34
Merge pull request #6787 from ThomasWaldmann/chmod-optional-1.2
SaveFile: the chmod is optional, fixes #6786
2022-06-23 18:07:02 +02:00
Thomas Waldmann
89e24847b9 SaveFile: the chmod is optional, fixes #6786
some filesystems do not support chmod, just ignore if it is failing.
2022-06-23 17:43:21 +02:00
TW
7ee4b7035b
Merge pull request #6779 from ThomasWaldmann/paths-from-normpath-1.2
create --paths-from-(stdin|command): normalize paths, fixes #6778
2022-06-22 00:20:20 +02:00
Thomas Waldmann
ec2bf8e45d create --paths-from-(stdin|command): normalize paths, fixes #6778 2022-06-20 13:44:35 +02:00
TW
97c5c54a0c
Merge pull request #6775 from wizeman/fix-obfuscate-1.2
fix test_obfuscate byte accounting (backport #6773 to 1.2-maint)
2022-06-14 17:29:24 +02:00
Ricardo M. Correia
333320ad56 fix test_obfuscate byte accounting 2022-06-14 16:06:49 +02:00
TW
bab00fb47b
Merge pull request #6769 from ThomasWaldmann/safe-secure-erase-1.2
secure_erase: avoid collateral damage, fixes #6768
2022-06-13 19:41:38 +02:00
Thomas Waldmann
afcebf32f7 secure_erase: avoid collateral damage, fixes #6768
if a hardlink copy of a repo was made and a new repo config
shall be saved, do NOT fill in random garbage before deleting
the previous repo config, because that would damage the hardlink
copy.
2022-06-13 15:47:50 +02:00
TW
73b97f339b
Merge pull request #6765 from targhs/doc/correct-installation-shell-syntax
Correct shell syntax for installation using git
2022-06-12 19:48:03 +02:00
targhs
08629e4d83 Commit shell syntax for installation using git 2022-06-12 22:37:37 +05:30
TW
7f8a5bb9c3
Merge pull request #6753 from ThomasWaldmann/rel121
Release 1.2.1
2022-06-05 23:43:32 +02:00
Thomas Waldmann
9fad4ba1cb build_man 2022-06-05 20:14:26 +02:00
Thomas Waldmann
a7c1c1cb16 build_usage 2022-06-05 20:13:46 +02:00
Thomas Waldmann
6c0842ec42 update CHANGES 2022-06-05 20:09:06 +02:00
TW
b0c726abae
Merge pull request #6752 from ThomasWaldmann/vagrant-updates
Vagrant updates (1.2)
2022-06-05 20:03:03 +02:00
Thomas Waldmann
d8102774b6 vagrant: increase VMCPUS and xdistn from 4 to 16
esp. the darwin64 box based tests take ages, let's see
if they get faster with this.
2022-06-05 19:56:29 +02:00
TW
7475e661bf
Merge pull request #6751 from ThomasWaldmann/update-changes-1.2
update CHANGES (1.2)
2022-06-05 18:36:37 +02:00
TW
eeb55c10c4
Merge pull request #6749 from fantasya-pbem/docs/4776_FAQ_swapped-targets_main
[DOCS] #4776 - FAQ: How to swap backup media
2022-06-05 18:33:50 +02:00
Thalian
cfcf99ccb5 [DOCS] #4776 - FAQ: How to swap backup media
Backport from master.
2022-06-05 18:22:23 +02:00
Thomas Waldmann
4ae08ee972 update CHANGES 2022-06-05 18:18:49 +02:00
TW
cfc623e250
Merge pull request #6748 from ThomasWaldmann/update-changes-rel1118-1.2
update CHANGES with 1.1.18 changelog
2022-06-05 18:08:52 +02:00
Thomas Waldmann
677db66e9d update CHANGES with 1.1.18 changelog 2022-06-05 17:45:48 +02:00
Thomas Waldmann
96c748c1d2 vagrant: add ubuntu "jammy" 22.04 box 2022-06-05 17:35:05 +02:00
TW
7ab36ceb76
Merge pull request #6742 from ThomasWaldmann/msgpack104-1.2
msgpack 1.0.4 / py 3.11 (1.2-maint)
2022-06-03 10:37:31 +02:00
Thomas Waldmann
6d024961aa add python 3.11 to pypi metadata 2022-06-03 10:05:56 +02:00
Thomas Waldmann
d1ef35b4f0 CI: also test on python 3.11-dev 2022-06-03 10:05:56 +02:00
Thomas Waldmann
de61d4953b allow msgpack 1.0.4, fixes #6716 2022-06-03 10:05:44 +02:00
TW
03827bc684
Merge pull request #6738 from ThomasWaldmann/vagrant-updates-1.2
Vagrant updates (1.2-maint)
2022-06-01 20:19:55 +02:00
Thomas Waldmann
354b014b19 vagrant/testing: upgrade development.lock.txt
esp. the Cython version upgrade to 0.29.30 is important for python 3.11.
2022-06-01 19:51:55 +02:00
Thomas Waldmann
6b9a66b5fa vagrant: use pyinstaller 4.10
when installed via pip, this automatically build the bootloader now.
2022-06-01 19:49:37 +02:00
Thomas Waldmann
6063c21bd9 vagrant: use python 3.9.13 for binary build 2022-06-01 19:48:10 +02:00
TW
8370eea9e0
Merge pull request #6731 from KN4CK3R/backport-6724-1.2
Backport make constants for files cache mode more clear (#6724, 1.2)
2022-05-30 16:02:53 +02:00
Elmar Hoffmann
bf31030d05 make constants for files cache mode more clear (#6724)
* make constants for files cache mode more clear

Traditionally, DEFAULT_FILES_CACHE_MODE_UI and DEFAULT_FILES_CACHE_MODE
were - as the naming scheme implies - the same setting, one being the UI
representation as given to the --files-cache command line option and the
other being the same default value in the internal representation.

It happended that the actual value used in borg create always comes from
DEFAULT_FILES_CACHE_MODE_UI (because that does have the --files-cache
option) whereas for all other commands (that do not use the files cache) it
comes from DEFAULT_FILES_CACHE_MODE.

PR #5777 then abused this fact to implement the optimisation to skip loading
of the files cache in those other commands by changing the value of
DEFAULT_FILES_CACHE_MODE to disabled.
This however also changes the meaning of that variable and thus redesignates
it to something not matching the original naming anymore.

Anyone not aware of this change and the intention behind it looking at the
code would have a hard time figuring this out and be easily mislead.

This does away with the confusion making the code more maintainable by
renaming DEFAULT_FILES_CACHE_MODE to FILES_CACHE_MODE_DISABLED, making the
new intention of that internal default clear.

* make constant for files cache mode UI default match naming scheme
2022-05-30 15:31:26 +02:00
TW
5679eb16df
Merge pull request #6722 from ThomasWaldmann/debug-get-chunk-1.2
borg debug dump-repo-objs --ghost: new --segment=S --offset=O options
2022-05-28 00:33:49 +02:00
Thomas Waldmann
49f191bc4c borg debug dump-repo-objs: new --segment=S --offset=O options
the new options limit processing to segment S (and, optionally, also
to offset O), so you do not need to dump your complete repo to only
look at 1 segment (or 1 object).

note: there is no rpc api for scan_low_level, so this only works locally.
2022-05-27 23:29:45 +02:00
TW
1b231e79e2
Merge pull request #6720 from ThomasWaldmann/update-changes-1.2
update CHANGES (1.2)
2022-05-27 21:54:23 +02:00
Thomas Waldmann
b55bb4694d update CHANGES 2022-05-27 17:12:56 +02:00
TW
7d14302b12
Merge pull request #6718 from fantasya-pbem/task/6407_document-pattern-changes-backport
#6407 - Document Borg 1.2 pattern behavior change
2022-05-27 15:41:51 +02:00
Thalian
2694652e37 #6407 - Document Borg 1.2 pattern behavior change
Backport from master: Make clear that absolute paths always go into the matcher as if they are relative (without leading slash). Adapt all examples accordingly.
2022-05-27 15:14:01 +02:00
TW
371bb06dd1
Merge pull request #6700 from KN4CK3R/backport-6688-1.2
Backport Fix typos (#6688)
2022-05-16 00:08:41 +02:00
Andrea Gelmini
f4d7c32058 Fix typos (#6688)
fix typos

Co-authored-by: Thomas Waldmann <tw@waldmann-edv.de>
2022-05-15 23:43:50 +02:00
TW
39708849a2
Merge pull request #6695 from ThomasWaldmann/versions-mount-1archive-error-1.2
mount -o versions: give clear error msg instead of crashing
2022-05-15 19:52:43 +02:00
Thomas Waldmann
99ccd4f792 mount -o versions: give clear error msg instead of crashing
it does not make sense to request versions view if you only
look at 1 archive, but the code shall not crash in that case
as it did, but give a clear error msg.
2022-05-15 00:40:53 +02:00
Christopher Klooz
c3bbb5e57a
docs: authentication primitives: improved security and performance infos (1.2) (#6692)
docs: authentication primitives: improved security and performance infos
2022-05-14 22:56:39 +02:00
TW
fd4503cd30
Merge pull request #6683 from ThomasWaldmann/fix-archive-progress-json-1.2
show_progress: add finished=true/false to archive_progress json
2022-05-08 19:45:53 +02:00
TW
247b3d9b55
Merge pull request #6686 from ThomasWaldmann/fix-create-filter-1.2
fix create_filter_process exception handler, fixes #6681
2022-05-08 19:15:59 +02:00
Thomas Waldmann
b846ae9659 fix create_filter_process exception handler, fixes #6681
if cmd was falsy (e.g. None), there is no proc.
then, if "yield stream" raises an exception, the exception handler crashed at "proc.kill()".
2022-05-08 18:46:42 +02:00
Thomas Waldmann
9dff959f16 show_progress: add finished=true/false to archive_progress json, fixes #6570
also:
- remove empty values from final json
- add test
2022-05-08 18:38:10 +02:00
TW
ae417cccf6
Merge pull request #6679 from KN4CK3R/backport-6670-1.2
Backport check that borg does not require pytest for normal usage (#6670, 1.2)
2022-05-07 19:59:22 +02:00
TW
d72eb3b1cf
Merge pull request #6678 from KN4CK3R/backport-6659-1.2
Backport mention BORG_FILES_CACHE_SUFFIX as alternative to BORG_FILES_CACHE_TTL (#6659)
2022-05-07 19:57:52 +02:00
Thomas Waldmann
c7390383a0 check that borg does not require pytest for normal usage, fixes #6563
also: move the note about this to the very top of the affected modules.
2022-05-07 18:56:36 +02:00
Thomas Waldmann
6d6711768e docs: mention BORG_FILES_CACHE_SUFFIX as alternative to BORG_FILES_CACHE_TTL, fixes #5602 2022-05-07 18:47:41 +02:00
TW
bcac974df7
Merge pull request #6648 from ThomasWaldmann/key-algo-error-msg-1.2
give a more helpful error msg for unsupported encrypted key format
2022-04-27 11:03:15 +02:00
Thomas Waldmann
25390de2c7 give a more helpful error msg for unsupported key format, fixes #6561 2022-04-24 22:03:28 +02:00
Thomas Waldmann
05d7ee9ed8 give a more helpful error msg for unsupported encrypted key format, fixes #6561 2022-04-24 21:55:41 +02:00
TW
1311a7d7a7
Merge pull request #6645 from hexagonrecursion/1.2-faq
[1.2] Add a troubleshooting note to the FAQ
2022-04-24 13:57:02 +02:00
Andrey Bienkowski
622ec1a181 Add a troubleshooting note to the FAQ 2022-04-24 11:27:37 +03:00
TW
65e371999d
Merge pull request #6636 from ThomasWaldmann/docs-files-cache-1.2
FAQ: add a hint about --debug-topic=files_cache
2022-04-20 13:01:56 +02:00
Thomas Waldmann
56262b57bd FAQ: add a hint about --debug-topic=files_cache 2022-04-20 13:00:34 +02:00
TW
26b46dd1f4
Merge pull request #6629 from ThomasWaldmann/fix-iec-1.2
fix --iec mode output for borg delete and prune
2022-04-19 23:39:26 +02:00
TW
b2d0af9487
Merge pull request #6632 from ThomasWaldmann/fix-info-authenticated-1.2
info: fix authenticated mode repo to show "Encrypted: No", fixes #6462
2022-04-19 23:38:54 +02:00
Thomas Waldmann
c5f3214d8a info: fix authenticated mode repo to show "Encrypted: No", fixes #6462 2022-04-19 22:10:44 +02:00
TW
890b627860
Merge pull request #6627 from ThomasWaldmann/fix-files-cache-6353-1.2
fix transaction rollback: use files cache filename as found in txn.active
2022-04-19 21:57:55 +02:00
Thomas Waldmann
cc04253afd prune: fix --stats --iec output to use binary units, see #6606 2022-04-19 21:51:55 +02:00
Thomas Waldmann
0ddb1fa194 delete: fix --stats --iec output to use binary units, see #6606 2022-04-19 21:50:26 +02:00
Thomas Waldmann
8d160b6a8e fix transaction rollback: use files cache filename as found in txn.active, fixes #6353 2022-04-19 21:17:50 +02:00
TW
55f9028611
diff: support presence change for blkdev, chrdev and fifo items (1.2-maint) (#6615)
diff: support presence change for blkdev, chrdev and fifo items

also: refactor / clean up / reuse code.
2022-04-19 16:47:08 +02:00
TW
5619b5e2bd
Merge pull request #6620 from ThomasWaldmann/secure-erase-msg-1.2
remove stray punctuation from secure-erase message
2022-04-18 10:01:40 +02:00
TW
390b3127d0
Merge pull request #6618 from ThomasWaldmann/invalid-repo-msg-1.2
better error msg for defect or unsupported repo configs, fixes #6566
2022-04-18 09:52:52 +02:00
Jakub Wilk
291901717d remove stray punctuation from secure-erase message 2022-04-18 09:33:26 +02:00
Thomas Waldmann
e32760ee47 better error msg for defect or unsupported repo configs, fixes #6566 2022-04-18 09:28:30 +02:00
TW
9dec811077
Merge pull request #6613 from ThomasWaldmann/fix-pre12-meta-1.2
pre12-meta cache: do not use the cache if want_unique is True, fixes #6612
2022-04-18 09:27:02 +02:00
TW
638184ae6f
Merge pull request #6614 from ThomasWaldmann/require-setuptools-scm-via-pyproject-1.2
setuptools_scm: also require it via pyproject.toml
2022-04-18 08:03:02 +02:00
Thomas Waldmann
6ab17ee4e1 setuptools_scm: also require it via pyproject.toml
we have this in setup_requires in setup.py, but i also added it to
pyproject.toml - so we can be sure it is installed no matter what.

**configuration** of setuptools_scm is done the old way in setup.py
here in 1.2-maint, in master we have switched that over to pyproject.toml.
2022-04-18 05:00:17 +02:00
Thomas Waldmann
2a15ccf5ac pre12-meta cache: do not use the cache if want_unique is True, fixes #6612
we can't cache usize, it needs to get dynamically calculated.
2022-04-18 04:37:00 +02:00
TW
6eb0bee328
Merge pull request #6591 from ThomasWaldmann/fix-md-chunks-processing-1.2
metadata stream can produce all-zero chunks, fixes #6587
2022-04-14 03:53:52 +02:00
Thomas Waldmann
e1fbe1782f metadata stream can produce all-zero chunks, fixes #6587
all-zero chunks are propagated as:
CH_ALLOC, data=None, size=len(zeros)

other chunks are:
CH_DATA, data=data, size=len(data)

also: remove the comment with the wrong assumption
2022-04-14 00:09:53 +02:00
TW
d6f7056d9d
Merge pull request #6589 from ThomasWaldmann/docs-virt-1.2
virtualisation speed tips
2022-04-13 23:24:59 +02:00
Thomas Waldmann
08ed786f6d virtualisation speed tips 2022-04-13 23:08:39 +02:00
TW
7a3056092e
Merge pull request #6582 from ThomasWaldmann/deleted-key-1.2
load_key: no key is same as empty key, fixes #6441
2022-04-12 20:09:10 +02:00
Thomas Waldmann
7fc1d75cd3 load_key: no key is same as empty key, fixes #6441
when migrating from repokey to keyfile, we just store an empty key into the repo config,
because we do not have a "delete key" RPC api. thus, empty key means "there is no key".

here we fix load_key, so that it does not behave differently for no key and empty key:
in both cases, it just returns an empty value.

additionally, we strip the value we get from the config, so whitespace does not matter.

All callers now check for the repokey not being empty, otherwise RepoKeyNotFoundError
is raised.
2022-04-12 19:43:48 +02:00
TW
fddd0c93fa
Merge pull request #6581 from ThomasWaldmann/docs-max-duration-1.2
docs: improve borg check --max-duration description
2022-04-12 19:40:51 +02:00
TW
063adc1799
Merge pull request #6579 from ThomasWaldmann/compact-docs-1.2
docs: borg compact --cleanup-commits also runs a normal compaction
2022-04-12 18:53:53 +02:00
Thomas Waldmann
ec90a065fb docs: improve borg check --max-duration description 2022-04-12 18:45:03 +02:00
TW
8d632c0fcc
Merge pull request #6574 from ThomasWaldmann/more-robust-iterator-1.2
borg check improvements (1.2)
2022-04-12 18:13:36 +02:00
TW
19f9247f65
Merge pull request #6576 from ThomasWaldmann/repo-tags-docs-1.2
docs: fix values of TAG bytes, fixes #6515
2022-04-12 18:13:05 +02:00
Thomas Waldmann
3bacf4ac39 docs: borg compact --cleanup-commits also runs a normal compaction, fixes #6324 2022-04-12 18:11:38 +02:00
Thomas Waldmann
bb6188da49 docs: fix values of TAG bytes, fixes #6515 2022-04-12 17:58:13 +02:00
Thomas Waldmann
c8f160068e check archives: improve error handling for corrupt archive metadata block
this is similar to #4777.

borg check must not crash if an archive metadata block does not decrypt.

Instead, report the archive_id, remove the archive from the manifest and skip to the next archive.
2022-04-12 17:45:48 +02:00
Thomas Waldmann
151fe5f348 check archive: make robust_iterator more robust, fixes #4777
borg check must not crash if an archive metadata chunk does not decrypt.

Instead, report the chunk and skip to the next one.
2022-04-12 17:45:17 +02:00
TW
70e30dea4d
Merge pull request #6558 from bcat/1.2-maint
(docs) 1.2: Recommend umask for passphrase file perms
2022-04-10 14:00:37 +02:00
Jonathan Rascher
4b58dafd31 (docs) Recommend umask for passphrase file perms
The previous sample for creating a ~/.borg-passphrase file creates it first and then chmod's it to 400 permissions. That's probably fine in practice, but means there's a tiny window where the passphrase file is sitting with default permissions (likely world readable, depending on the system umask).

It seems safer to first change the umask to remove all group & world bits (0077) _before_ creating the file. To be polite and avoid messing with the user's previous umask, we do this in a subshell. (Note that umask 0077 leads to a mode of 600 rather than the previous 400, because removing the owner write bit doesn't seem to buy much since the owner can just chmod the file anyway.)
2022-04-09 23:58:45 -05:00
TW
b602352d34
Merge pull request #6545 from ThomasWaldmann/add-pyproject.toml-1.2
add pyproject.toml, fix sys.path, fixes #6466
2022-04-07 21:27:07 +02:00
TW
aa55aef2b9
Merge pull request #6543 from ThomasWaldmann/fix-progress-archivename-1.2
escape % chars in archive name, fixes #6500
2022-04-07 20:22:06 +02:00
Thomas Waldmann
82a80bf760 add pyproject.toml, fix sys.path, fixes #6466
setup.py: add parent to sys.path

When using pyproject.toml the parent of setup.py is not on sys.path by default.

See <pypa/setuptools#3134>.
2022-04-07 18:48:48 +02:00
Thomas Waldmann
a4f7eeb179 escape % chars in archive name, fixes #6500
also: fix percentage format for float value.
2022-04-07 18:03:25 +02:00
TW
a7328edd58
Merge pull request #6532 from bket/1.2_fix_#2055
1.2 - fix OpenBSD symlink mode test failure (#2055)
2022-04-04 21:41:07 +02:00
TW
f5927b6b49
Merge pull request #6528 from ThomasWaldmann/fix-ipv6-url-parsing-1.2
fix scp repo url parsing for ip v6 addrs, fixes #6526
2022-04-04 20:39:28 +02:00
Björn Ketelaars
b467d50c35 1.2 - Fix OpenBSD symlink mode test failure (#2055)
OpenBSD does not have `lchmod()` causing `os.lchmod` to be unavailable
on this platform. As a result ArchiverTestCase::test_basic_functionality
fails when run manually (#2055).

OpenBSD does have `fchmodat()`, which has a flag that makes it behave
like `lchmod()`. In Python this can be used via `os.chmod(path, mode,
follow_symlinks=False)`.

As of Python 3.3 `os.lchmod(path, mode)` is equivalent to
`os.chmod(path, mode, follow_symlinks=False)`. As such, switching to the
latter is preferred as it enables more platforms to do the right thing.
2022-04-04 19:24:28 +02:00
Thomas Waldmann
40f1f9ddee use same host regex for ssh and scp style, refactor/clean up
although bug #6526 did not show with ssh style URLs, we should
not have different regexes for the host part for ssh and scp style.

thus i extracted the host_re from both and also cleaned up a bit.
2022-04-03 21:33:26 +02:00
Thomas Waldmann
e332acb334 fix scp repo url parsing for ip v6 addrs, fixes #6526
added a negative lookahead/lookbehind to make sure an ipv6 addr
(enclosed in square brackets) does not get badly matched by the
regex part intended for hostnames and ipv4 addrs only.

the other part of that regex which is actually intended to match
ipv6 addrs only matches if they are enclosed in square brackets.

also added tests for ssh and scp style repo URLs with ipv6 addrs
in brackets.

also: made regex more readable, putting these 2 cases on separate lines.
2022-04-03 21:30:28 +02:00
TW
e5e360d5b6
Merge pull request #6507 from ThomasWaldmann/update-security-support-1.2
borg 1.2 is security supported
2022-03-30 00:11:57 +02:00
Thomas Waldmann
017f9b2102 borg 1.2 is security supported 2022-03-29 23:55:25 +02:00
TW
28c7494455
Merge pull request #6503 from aspargas2/1.2-maint
1.2-maint backport: delete: add repository id and location to prompt
2022-03-28 18:42:36 +02:00
Thomas Deutschmann
821d814af3 delete: add repository id and location to prompt
Closes: https://github.com/borgbackup/borg/issues/6453
2022-03-28 10:16:53 -04:00
TW
b5443da6cb
Merge pull request #6493 from ThomasWaldmann/use-compare_digest-1.2
use hmac.compare_digest instead of ==, fixes #6470
2022-03-26 19:48:05 +01:00
TW
4ecf0d4d78
Merge pull request #6491 from ThomasWaldmann/crypto-fixes-1.2
avoid losing the key (old crypto)
2022-03-26 19:05:54 +01:00
Thomas Waldmann
b75079c0f8 use hmac.compare_digest instead of ==, fixes #6470 2022-03-26 18:52:41 +01:00
Thomas Waldmann
3e91694a0a avoid losing the key (old crypto)
if we just have a pointer to a bytes object which might go out of scope, we can lose it.

also: cython can directly assign a bytes object into a same-size char array.
2022-03-26 18:32:44 +01:00
TW
2e45e19e02
Merge pull request #6488 from ThomasWaldmann/update-ubuntu-link-1.2
docs: update link to ubuntu packages, fixes #6485
2022-03-26 18:20:54 +01:00
Thomas Waldmann
c14bc52189 docs: update link to ubuntu packages, fixes #6485 2022-03-26 18:07:03 +01:00
TW
df9322c4a9
Merge pull request #6475 from bket/unused-code-1.2
1.2 - Remove unused code
2022-03-21 19:51:09 +01:00
Björn Ketelaars
71fa056c47 1.2 - Remove unused code
#6473 Removed AEAD ciphers AES-OCB and CHACHA20-POLY1305 from 1.2. As a
result some additional code can be removed.

Passes regression tests.
2022-03-21 18:54:50 +01:00
TW
87f0b9803b
Merge pull request #6473 from ThomasWaldmann/remove-aead-1.2
remove AEAD ciphers AES-OCB and CHACHA20-POLY1305, fixes #6472
2022-03-20 23:44:40 +01:00
Thomas Waldmann
aa57a3cb57 remove AEAD ciphers AES-OCB and CHACHA20-POLY1305, fixes #6472
not used in 1.2.x, we'll start using them in 1.3.
2022-03-20 23:05:30 +01:00
TW
d41908166f
Merge pull request #6435 from hexagonrecursion/1-2-fallthrough
1.2: Make switch fallthrough explicit
2022-03-10 12:04:12 +01:00
TW
e25d6c8c4b
Merge pull request #6436 from hexagonrecursion/1-2-numeric
1.2: use --numeric-ids in pull doc
2022-03-10 11:55:42 +01:00
Michael Bauer
1345f06f2b use --numeric-ids in pull doc
replace flag --numeric-owner with --numeric-ids
2022-03-10 08:34:27 +03:00
Andrey Bienkowski
a58fd3db5c 1.2: Make switch fallthrough explicit 2022-03-10 08:24:23 +03:00
TW
791720407b
Merge pull request #6432 from hexagonrecursion/1-2-cflags
1.2: Allow extra compiler flags for every extension build
2022-03-10 00:13:44 +01:00
James Buren
793d543328 Allow extra compiler flags for every extension build
This is mainly intended for explicit warnings but it can be
used for other flags as well.

Conflicts:
	setup.py
2022-03-10 00:50:59 +03:00
TW
f698c12129
Merge pull request #6403 from ThomasWaldmann/fix-savefile-mode-1.2
respect umask for files / dirs (1.2)
2022-03-09 16:53:35 +01:00
braewoods
8b4c501d8d
[1.2-maint] Backport implicit warning patches from master (#6427)
* suppress -Wimplicit-fallthrough warning

These instances of implicit switch case fallthrough appear to be
intentional. Add comments that the compiler understands to suppress
the false positive warning.
2022-03-09 16:10:21 +01:00
TW
450610b168
Merge pull request #6423 from ThomasWaldmann/fix-cython-warnings-1.2
fix "useless trailing comma" cython warnings
2022-03-08 22:19:47 +01:00
Thomas Waldmann
dc811bda6f fix "'HMAC_CTX' already defined" cython warning 2022-03-08 21:47:14 +01:00
Thomas Waldmann
cd629d32cb fix "useless trailing comma" cython warnings 2022-03-08 21:27:20 +01:00
TW
7a1d12d007
Merge pull request #6418 from hexagonrecursion/bp12-unicode
1.2-maint: ‘PyUnicode_AsUnicode’ is deprecated
2022-03-07 20:14:15 +01:00
Andrey Bienkowski
f05036cbcb ‘PyUnicode_AsUnicode’ is deprecated
Fix compilation warnings:
```
gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/opt/hostedtoolcache/Python/3.9.10/x64/include/python3.9 -c src/borg/platform/posix.c -o build/temp.linux-x86_64-3.9/src/borg/platform/posix.o
src/borg/platform/posix.c: In function ‘__pyx_pf_4borg_8platform_5posix_2swidth’:
src/borg/platform/posix.c:1572:3: warning: ‘PyUnicode_AsUnicode’ is deprecated [-Wdeprecated-declarations]
 1572 |   __pyx_t_2 = __Pyx_PyUnicode_AsUnicode(__pyx_v_s); if (unlikely((!__pyx_t_2) && PyErr_Occurred())) __PYX_ERR(0, 19, __pyx_L1_error)
      |   ^~~~~~~~~
In file included from /opt/hostedtoolcache/Python/3.9.10/x64/include/python3.9/unicodeobject.h:1026,
                 from /opt/hostedtoolcache/Python/3.9.10/x64/include/python3.9/Python.h:93,
                 from src/borg/platform/posix.c:19:
/opt/hostedtoolcache/Python/3.9.10/x64/include/python3.9/cpython/unicodeobject.h:580:45: note: declared here
  580 | Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode(
      |                                             ^~~~~~~~~~~~~~~~~~~
```

Ref: https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_AsUnicode
2022-03-07 21:40:39 +03:00
TW
20a9df18f7
Merge pull request #6413 from aspargas2/1.2-maint
Backport: fix codeql complaining about missing headers needed by borg
2022-03-07 17:59:53 +01:00
aspargas2
2425f54bdb tweak what is backported, as requested
- don't backport `pyproject.toml` or related changes
- install some additional -dev packages with `apt-get` for CodeQL
- run CodeQL in a python venv
2022-03-07 10:14:22 -05:00
TW
bb76dca114
Merge pull request #6414 from hexagonrecursion/bp-blake
1.2-maint: hmac and blake2b minor optimizations and cleanups
2022-03-06 14:39:51 +01:00
Thomas Waldmann
ce72a87f2d fixup: fix SELFTEST_COUNT 2022-03-06 11:31:05 +03:00
Thomas Waldmann
65ccbc2c69 fixup: remove now unused import 2022-03-06 11:31:05 +03:00
Thomas Waldmann
8dd2612fc6 remove the blake2b compat checker script
this was used to compare compatibility of our vendored
blake2b code (which we do not have any more) against the
python stdlib blake2b code (which we always use now anyway).
2022-03-06 11:31:05 +03:00
Thomas Waldmann
45ef108d46 remove our blake2b_128/256 tests
as we're just calling python stdlib there,
we can assume that they have tests for it.

 Conflicts:
	src/borg/testsuite/crypto.py
2022-03-06 11:30:58 +03:00
Thomas Waldmann
c2211a7ef9 remove our hmac_sha256 tests
as we're just calling python stdlib there,
we can assume that they have tests for it.

 Conflicts:
	src/borg/testsuite/crypto.py
2022-03-06 11:28:27 +03:00
Thomas Waldmann
72ccafb4b8 hmac.digest: some more minor optimizations
also some cosmetic changes:
- import hmac module
- use hmac.compare_digest
2022-03-06 11:26:04 +03:00
Thomas Waldmann
bcd1d49d3b hmac_sha256: replace own cython wrapper code by hmac.digest python stdlib (since py38)
i measured performance of both: pretty much the same.
2022-03-06 11:26:04 +03:00
Thomas Waldmann
4fb6df813a fix codeql complaining about missing headers needed by borg
thus:
- install requirements first
- codeql init
- build borg
- codeql analyzse
2022-03-05 23:28:37 -05:00
aspargas2
aa27294927 fix codeql complaining about missing cython
backports commits 6cbb7d6, 142bb0e, 4df8255, and 30c145e
2022-03-05 23:21:20 -05:00
TW
d0fb234f46
Merge pull request #6404 from ThomasWaldmann/import-tar-fixes-1.2
import-tar fixes
2022-03-05 14:26:59 +01:00
TW
8abb0aa7ab
Merge pull request #6375 from ThomasWaldmann/fix-6374-1.2
create: skip with warning if opening the parent dir of recursion root fails, fixes #6374
2022-03-05 14:18:40 +01:00
Thomas Waldmann
7dc800fecd kill filter process in case of borg exceptions, fixes #6401
in the finally-block, we wait for the filter process to die. but it only dies
voluntarily if all data was processed by the filter and it terminates due to EOF.

otoh, if borg has thrown an early exception, e.g. "archive already exists",
we need to kill the filter process to bring it to an early end. in that
case, we also do not need to check the filter rc, because we know we killed it.
2022-03-04 23:33:53 +01:00
Thomas Waldmann
33192e5e5d import-tar: fix mtime type bug
looks like with a .tar file created by the tar tool,
tarinfo.mtime is a float [s]. So, after converting to
nanoseconds, we need to cast to int because that's what
Item.mtime wants.

also added a safe_ns() there to clip values to the safe range.
2022-03-04 23:33:53 +01:00
TW
ea668417c9
Merge pull request #6405 from ThomasWaldmann/fix-ci
fix wrong branch name in github actions
2022-03-04 23:32:47 +01:00
Thomas Waldmann
412e39b898 fix wrong branch name in github actions 2022-03-04 22:50:23 +01:00
Thomas Waldmann
f5a47d86e3 ensure_dir: respect umask for created directory modes, fixes #6400
we tried to be very private / secure here, but that created the issue
that a less secure umask (like e.g. 0o007) just did not work.

to make the umask work, we must start from 0o777 mode and let the
umask do its work, like e.g. 0o777 & ~0o007 --> 0o770.

with borg's default umask of 0o077, it usually ends up being 0o700,
so only permissions for the user (not group, not others).
2022-03-04 21:24:42 +01:00
Thomas Waldmann
9ea1d2a7d6 SaveFile: respect umask for final file mode, fixes #6400 2022-03-04 20:53:10 +01:00
TW
057ae69537
Merge pull request #6384 from ThomasWaldmann/pyupgrade-38-1.2
run pyupgrade (1.2-maint)
2022-02-27 22:52:43 +01:00
Thomas Waldmann
8edb1dc085 manual formatting fixes (cosmetic / pep8) 2022-02-27 21:13:04 +01:00
Thomas Waldmann
c4ed840c7b pyupgrade --py38-plus ./**/*.py 2022-02-27 21:12:44 +01:00
TW
6c243b2c28
Merge pull request #6381 from ThomasWaldmann/remove-blake2-docs-1.2
remove blake2 docs, blake2 code not bundled any more, fixes #6371
2022-02-27 14:44:11 +01:00
Thomas Waldmann
51a676cc6f remove blake2 docs, blake2 code not bundled any more, fixes #6371 2022-02-27 14:43:27 +01:00
TW
97de7e1fe2
Merge pull request #6380 from ThomasWaldmann/fix-zstd-include-1.2
fix zstd.h include for bundled zstd, fixes #6369
2022-02-27 14:39:09 +01:00
Thomas Waldmann
9390d2712b fix zstd.h include for bundled zstd, fixes #6369 2022-02-27 14:35:19 +01:00
Thomas Waldmann
da0ddacc54 create: skip with warning if opening the parent dir of recursion root fails, fixes #6374 2022-02-27 02:40:15 +01:00
TW
c2b76adb19
Merge pull request #6373 from braewoods/warnings
[1.2-maint] fix multiple warnings related to _hashindex.c
2022-02-26 23:42:22 +01:00
James Buren
1618c98975 src/borg/cache_sync/unpack.h: fix compiler warnings
The key argument being sent to hashindex_get and hashindex_set by
multiple functions is a different signedness from what the functions
expect. This resolves the issue by changing the key type in the
unpack_user struct to unsigned char.
2022-02-26 16:13:07 -06:00
James Buren
4427c16d31 src/borg/_hashindex.c: fix compiler warnings
The value argument of hashindex_set is causing harmless pointer type
mismatches. This resolves the issue by changing the type to void*
which silences these types of warnings.
2022-02-26 16:13:02 -06:00
TW
d88d1674b7
Merge pull request #6367 from braewoods/warnings
[1.2-maint] src/borg/compress.pyx: fix compiler warning, closes #6365
2022-02-26 20:42:04 +01:00
James Buren
8e640ae0f3 src/borg/compress.pyx: fix compiler warning, closes #6365
This resolves a compiler warning from the generated code that
resulted from a comparison of two local variables of different
signedness. The issue is resolved by changing the type of both
to int since this seems like the safest choice available.
2022-02-26 13:20:39 -06:00
TW
c6f284d43c
Merge pull request #6364 from braewoods/warnings
[1.2-maint] src/borg/crypto/low_level.pyx: fix compiler warning
2022-02-26 00:40:55 +01:00
James Buren
067dd10027 src/borg/crypto/low_level.pyx: fix compiler warning
The generated source code was producing a compiler warning due to
the pointers differing in constness. The called function expects
a non-const pointer while the generated code produces a const pointer
via a cast. This changes the cast to drop 'const' to make the compiler
happy.
2022-02-25 17:36:48 -06:00
Thomas Waldmann
f81c62f894 vagrant: darwin64: remove fakeroot, fixes #6314
deprecated / unsupported / 404.
2022-02-25 23:48:03 +01:00
TW
0fb546978a
Merge pull request #6358 from hexagonrecursion/apt-get-1.2
s/apt/apt-get/ (1.2)
2022-02-25 21:02:39 +01:00
TW
04712a76dc
Merge pull request #6359 from hexagonrecursion/order-1.2
docs: Clarify on-disk order and size of log entry fields (1.2)
2022-02-25 20:50:59 +01:00
Julian Picht
e49a1b5d9b docs: Clarify on-disk order and size of log entry fields (#6357)
docs: clarify on-disk order and size of log entry fields

The order of the fields of a log entry on disk is CRC32 first, the docs had the size first.

I tried to make this list similar to the HashIndex struct description.
2022-02-25 15:03:21 +03:00
Andrey Bienkowski
29ce1fc818 s/apt/apt-get/
> WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
2022-02-25 14:44:11 +03:00
TW
6f18167873
Merge pull request #6348 from ThomasWaldmann/nodashes-1.2
docs: do not transform --/--- to unicode dashes
2022-02-23 20:58:44 +01:00
Thomas Waldmann
f5116a7e67 docs: do not transform --/--- to unicode dashes 2022-02-23 20:08:27 +01:00
626 changed files with 117604 additions and 68662 deletions

24
.coveragerc Normal file
View file

@ -0,0 +1,24 @@
[run]
branch = True
disable_warnings = module-not-measured
source = src/borg
omit =
*/borg/__init__.py
*/borg/__main__.py
*/borg/_version.py
*/borg/fuse.py
*/borg/support/*
*/borg/testsuite/*
*/borg/hash_sizes.py
[report]
exclude_lines =
pragma: no cover
pragma: freebsd only
pragma: unknown platform only
def __repr__
raise AssertionError
raise NotImplementedError
if 0:
if __name__ == .__main__.:
ignore_errors = True

View file

@ -1,2 +0,0 @@
# Migrate code style to Black
7957af562d5ce8266b177039783be4dc8bdd7898

5
.github/FUNDING.yml vendored
View file

@ -1,6 +1,5 @@
# These are supported funding model platforms
github: borgbackup
liberapay: borgbackup
open_collective: borgbackup
# github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
# liberapay: borgbackup
custom: ['https://www.borgbackup.org/support/fund.html']

View file

@ -1,54 +1,56 @@
<!--
Thank you for reporting an issue.
*IMPORTANT* Before creating a new issue, please look around:
- BorgBackup documentation: https://borgbackup.readthedocs.io/en/stable/index.html
*IMPORTANT* - *before* creating a new issue please look around:
- Borgbackup documentation: http://borgbackup.readthedocs.io/en/stable/index.html
- FAQ: https://borgbackup.readthedocs.io/en/stable/faq.html
- Open issues in the GitHub tracker: https://github.com/borgbackup/borg/issues
and
- open issues in Github tracker: https://github.com/borgbackup/borg/issues
If you cannot find a similar problem, then create a new issue.
Please fill in as much of the template as possible.
-->
## Have you checked the BorgBackup docs, FAQ, and open GitHub issues?
## Have you checked borgbackup docs, FAQ, and open Github issues?
No
## Is this a bug/issue report or a question?
## Is this a BUG / ISSUE report or a QUESTION?
Bug/Issue/Question
Invalid
## System information. For client/server mode, post info for both machines.
## System information. For client/server mode post info for both machines.
#### Your Borg version (borg -V).
#### Your borg version (borg -V).
#### Operating system (distribution) and version.
#### Hardware/network configuration and filesystems used.
#### Hardware / network configuration, and filesystems used.
#### How much data is handled by Borg?
#### How much data is handled by borg?
#### Full Borg command line that led to the problem (leave out excludes and passwords).
#### Full borg commandline that lead to the problem (leave away excludes and passwords)
## Describe the problem you're observing.
#### Can you reproduce the problem? If so, describe how. If not, describe troubleshooting steps you took before opening the issue.
#### Include any warnings/errors/backtraces from the system logs
#### Include any warning/errors/backtraces from the system logs
<!--
If this complaint relates to Borg performance, please include CRUD benchmark
If this complaint relates to borg performance, please include CRUD benchmark
results and any steps you took to troubleshoot.
How to run the benchmark: https://borgbackup.readthedocs.io/en/stable/usage/benchmark.html
How to run benchmark: http://borgbackup.readthedocs.io/en/stable/usage/benchmark.html
*IMPORTANT* Please mark logs and terminal command output, otherwise GitHub will not display them correctly.
*IMPORTANT* - Please mark logs and text output from terminal commands
or else Github will not display them correctly.
An example is provided below.
Example:
```
this is an example of how log text should be marked (wrap it with ```)
this is an example how log text should be marked (wrap it with ```)
```
-->

8
.github/PULL_REQUEST_TEMPLATE vendored Normal file
View file

@ -0,0 +1,8 @@
Thank you for contributing code to Borg, your help is appreciated!
Please, before you submit a pull request, make sure it complies with the
guidelines given in our documentation:
https://borgbackup.readthedocs.io/en/latest/development.html#contributions
**Please remove all above text before submitting your pull request.**

View file

@ -1,18 +0,0 @@
<!--
Thank you for contributing to BorgBackup!
Please make sure your PR complies with our contribution guidelines:
https://borgbackup.readthedocs.io/en/latest/development.html#contributions
-->
## Description
<!-- What does this PR do? Reference any related issues with "fixes #XXXX". -->
## Checklist
- [ ] PR is against `master` (or maintenance branch if only applicable there)
- [ ] New code has tests and docs where appropriate
- [ ] Tests pass (run `tox` or the relevant test subset)
- [ ] Commit messages are clean and reference related issues

View file

@ -1,24 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions:
patterns:
- "*"
- package-ecosystem: "pip"
directory: "/requirements.d"
ignore:
- dependency-name: "black"
schedule:
interval: "weekly"
cooldown:
semver-major-days: 90
semver-minor-days: 30
groups:
pip-dependencies:
patterns:
- "*"

View file

@ -1,38 +0,0 @@
name: Backport pull request
on:
pull_request_target:
types: [closed]
issue_comment:
types: [created]
permissions:
contents: write # so it can comment
pull-requests: write # so it can create pull requests
jobs:
backport:
name: Backport pull request
runs-on: ubuntu-24.04
timeout-minutes: 5
# Only run when pull request is merged
# or when a comment starting with `/backport` is created by someone other than the
# https://github.com/backport-action bot user (user id: 97796249). Note that if you use your
# own PAT as `github_token`, that you should replace this id with yours.
if: >
(
github.event_name == 'pull_request_target' &&
github.event.pull_request.merged
) || (
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.user.id != 97796249 &&
startsWith(github.event.comment.body, '/backport')
)
steps:
- uses: actions/checkout@v6
- name: Create backport pull requests
uses: korthout/backport-action@v4
with:
label_pattern: '^port/(.+)$'

View file

@ -1,30 +0,0 @@
# https://black.readthedocs.io/en/stable/integrations/github_actions.html#usage
# See also what we use locally in requirements.d/codestyle.txt — this should be the same version here.
name: Lint
on:
push:
paths:
- '**.py'
- 'pyproject.toml'
- '.github/workflows/black.yaml'
pull_request:
paths:
- '**.py'
- 'pyproject.toml'
- '.github/workflows/black.yaml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
lint:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: psf/black@87928e6d6761a4a6d22250e1fee5601b3998086e # 26.5.1
with:
version: "~= 24.0"

View file

@ -1,151 +0,0 @@
name: Canary (Unlocked Requirements)
on:
schedule:
- cron: '0 7 * * *' # Run at 07:00 UTC
workflow_dispatch: # Allow manual trigger
permissions:
contents: read
jobs:
canary_tests:
name: Canary (${{ matrix.os }}, ${{ matrix.python-version }}, ${{ matrix.toxenv }})
runs-on: ${{ matrix.os }}
timeout-minutes: 360
strategy:
fail-fast: false
matrix:
include:
# A representative subset of environments
- os: ubuntu-24.04
python-version: '3.11'
toxenv: py311-llfuse
- os: ubuntu-24.04
python-version: '3.12'
toxenv: py312-pyfuse3
- os: ubuntu-24.04
python-version: '3.14'
toxenv: py314-mfusepy
- os: macos-15
python-version: '3.14'
toxenv: py314-none
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install Linux packages
if: ${{ runner.os == 'Linux' }}
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y pkg-config build-essential
sudo apt-get install -y libssl-dev libacl1-dev liblz4-dev
if [[ "${{ matrix.toxenv }}" == *"llfuse"* ]]; then
sudo apt-get install -y libfuse-dev fuse
elif [[ "${{ matrix.toxenv }}" == *"pyfuse3"* || "${{ matrix.toxenv }}" == *"mfusepy"* ]]; then
sudo apt-get install -y libfuse3-dev fuse3
fi
- name: Install macOS packages
if: ${{ runner.os == 'macOS' }}
shell: bash
run: |
brew bundle install || true
- name: Install Python requirements (UNLOCKED)
shell: bash
run: |
python -m pip install --upgrade pip setuptools wheel
# Use UNLOCKED requirements to catch upstream breakages
pip install -r requirements.d/development.txt
- name: Install borgbackup
shell: bash
run: |
if [[ "${{ matrix.toxenv }}" == *"llfuse"* ]]; then
pip install -e ".[llfuse,cockpit]"
elif [[ "${{ matrix.toxenv }}" == *"pyfuse3"* ]]; then
pip install -e ".[pyfuse3,cockpit]"
elif [[ "${{ matrix.toxenv }}" == *"mfusepy"* ]]; then
pip install -e ".[mfusepy,cockpit]"
else
pip install -e ".[cockpit]"
fi
- name: Run tests (Canary)
shell: bash
run: |
if [[ "${{ matrix.toxenv }}" == *"-windows" ]]; then
python -m pytest -n4 --benchmark-skip -vv -rs -k "not remote" --cov=borg --cov-config=pyproject.toml --cov-report=xml --junitxml=test-results.xml
else
# Force tox to use the unlocked requirements in its environment creation
# by overriding the deps if possible, or just trusting it uses development.txt
# which we already installed in the root. Actually tox creates its own venv.
# We need to tell tox to use the unlocked file.
tox -e ${{ matrix.toxenv }} --override "env_run_base.deps=[-rrequirements.d/development.txt]"
fi
windows_canary:
if: true # can be used to temporarily disable the build
name: Canary (Windows)
runs-on: windows-latest
timeout-minutes: 180
env:
PY_COLORS: 1
MSYS2_ARG_CONV_EXCL: "*"
MSYS2_ENV_CONV_EXCL: "*"
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
- name: Install system packages
run: ./scripts/msys2-install-deps development
- name: Build python venv
run: |
# building cffi / argon2-cffi in the venv fails, so we try to use the system packages
python -m venv --system-site-packages env
. env/bin/activate
# python -m pip install --upgrade pip
# pip install --upgrade setuptools build wheel
pip install -r requirements.d/pyinstaller.txt
- name: Build
run: |
# build borg.exe
. env/bin/activate
pip install -e ".[cockpit,s3,sftp,rclone]"
mkdir -p dist/binary
pyinstaller -y --clean --distpath=dist/binary scripts/borg.exe.spec
# build sdist and wheel in dist/...
python -m build
- name: Run tests
run: |
# Ensure locally built binary in ./dist/binary/borg-dir is found during tests
export PATH="$GITHUB_WORKSPACE/dist/binary/borg-dir:$PATH"
borg.exe -V
. env/bin/activate
python -m pytest -n4 --benchmark-skip -vv -rs -k "not remote" --cov=borg --cov-config=pyproject.toml --cov-report=xml --junitxml=test-results.xml

View file

@ -4,702 +4,143 @@ name: CI
on:
push:
branches: [ master ]
tags:
- '2.*'
pull_request:
branches: [ master ]
branches: [ 1.2-maint ]
paths:
- '**.py'
- '**.pyx'
- '**.c'
- '**.h'
- '**.yml'
- '**.cfg'
- '**.ini'
- 'requirements.d/*'
- '!docs/**'
pull_request:
branches: [ 1.2-maint ]
paths:
- '**.py'
- '**.pyx'
- '**.c'
- '**.h'
- '**.yml'
- '**.toml'
- '**.cfg'
- '**.ini'
- 'requirements.d/*'
- '!docs/**'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-24.04
timeout-minutes: 5
runs-on: ubuntu-20.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: astral-sh/ruff-action@v3
security:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
python-version: 3.8
- name: Lint with flake8
run: |
python -m pip install --upgrade pip
pip install bandit[toml]
- name: Run Bandit
run: |
bandit -r src/borg -c pyproject.toml
pip install flake8
flake8 src scripts conftest.py
asan_ubsan:
pytest:
runs-on: ubuntu-24.04
timeout-minutes: 25
needs: [lint]
steps:
- uses: actions/checkout@v6
with:
# Just fetching one commit is not enough for setuptools-scm, so we fetch all.
fetch-depth: 0
fetch-tags: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install system packages
run: |
sudo apt-get update
sudo apt-get install -y pkg-config build-essential
sudo apt-get install -y libssl-dev libacl1-dev liblz4-dev
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.d/development.lock.txt
- name: Build Borg with ASan/UBSan
# Build the C/Cython extensions with AddressSanitizer and UndefinedBehaviorSanitizer enabled.
# How this works:
# - The -fsanitize=address,undefined flags inject runtime checks into our native code. If a bug is hit
# (e.g., buffer overflow, use-after-free, out-of-bounds, or undefined behavior), the sanitizer prints
# a detailed error report to stderr, including a stack trace, and forces the process to exit with
# non-zero status. In CI, this will fail the step/job so you will notice.
# - ASAN_OPTIONS/UBSAN_OPTIONS configure the sanitizers' runtime behavior (see below for meanings).
env:
CFLAGS: "-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined"
CXXFLAGS: "-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined"
LDFLAGS: "-fsanitize=address,undefined"
# ASAN_OPTIONS controls AddressSanitizer runtime tweaks:
# - detect_leaks=0: Disable LeakSanitizer to avoid false positives with CPython/pymalloc in short-lived tests.
# - strict_string_checks=1: Make invalid string operations (e.g., over-reads) more likely to be detected.
# - check_initialization_order=1: Catch uses that depend on static initialization order (C++).
# - detect_stack_use_after_return=1: Detect stack-use-after-return via stack poisoning (may increase overhead).
ASAN_OPTIONS: "detect_leaks=0:strict_string_checks=1:check_initialization_order=1:detect_stack_use_after_return=1"
# UBSAN_OPTIONS controls UndefinedBehaviorSanitizer runtime:
# - print_stacktrace=1: Include a stack trace for UB reports to ease debugging.
# Note: UBSan is recoverable by default (process may continue after reporting). If you want CI to
# abort immediately and fail on the first UB, add `halt_on_error=1` (e.g., UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1").
UBSAN_OPTIONS: "print_stacktrace=1"
# PYTHONDEVMODE enables additional Python runtime checks and warnings.
PYTHONDEVMODE: "1"
run: pip install -e .
- name: Run tests under sanitizers
env:
ASAN_OPTIONS: "detect_leaks=0:strict_string_checks=1:check_initialization_order=1:detect_stack_use_after_return=1"
UBSAN_OPTIONS: "print_stacktrace=1"
PYTHONDEVMODE: "1"
# Ensure the ASan runtime is loaded first to avoid "ASan runtime does not come first" warnings.
# We discover libasan/libubsan paths via gcc and preload them for the Python test process.
# the remote tests are slow and likely won't find anything useful
run: |
set -euo pipefail
export LD_PRELOAD="$(gcc -print-file-name=libasan.so):$(gcc -print-file-name=libubsan.so)"
echo "Using LD_PRELOAD=$LD_PRELOAD"
pytest -v --benchmark-skip -k "not remote"
native_tests:
needs: [lint]
permissions:
contents: read
id-token: write
attestations: write
needs: lint
strategy:
fail-fast: true
# noinspection YAMLSchemaValidation
matrix: >-
${{ fromJSON(
github.event_name == 'pull_request' && '{
"include": [
{"os": "ubuntu-24.04", "python-version": "3.11", "toxenv": "mypy"},
{"os": "ubuntu-24.04", "python-version": "3.11", "toxenv": "docs"},
{"os": "ubuntu-24.04", "python-version": "3.11", "toxenv": "py311-llfuse"},
{"os": "ubuntu-24.04", "python-version": "3.12", "toxenv": "py312-pyfuse3"},
{"os": "ubuntu-24.04", "python-version": "3.14", "toxenv": "py314-mfusepy"}
]
}' || '{
"include": [
{"os": "ubuntu-24.04", "python-version": "3.11", "toxenv": "py311-llfuse"},
{"os": "ubuntu-24.04", "python-version": "3.12", "toxenv": "py312-pyfuse3"},
{"os": "ubuntu-24.04", "python-version": "3.13", "toxenv": "py313-mfusepy"},
{"os": "ubuntu-24.04", "python-version": "3.14", "toxenv": "py314-pyfuse3", "binary": "borg-linux-glibc239-x86_64-gh"},
{"os": "ubuntu-24.04-arm", "python-version": "3.14", "toxenv": "py314-pyfuse3", "binary": "borg-linux-glibc239-arm64-gh"},
{"os": "macos-15", "python-version": "3.14", "toxenv": "py314-none", "binary": "borg-macos-15-arm64-gh"},
{"os": "macos-15-intel", "python-version": "3.14", "toxenv": "py314-none", "binary": "borg-macos-15-x86_64-gh"}
]
}'
) }}
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
python-version: '3.8'
toxenv: py38-fuse2
- os: ubuntu-20.04
python-version: '3.9'
toxenv: py39-fuse3
- os: ubuntu-20.04
python-version: '3.10'
toxenv: py310-fuse3
- os: ubuntu-20.04
python-version: '3.11'
toxenv: py311-fuse2
- os: ubuntu-22.04
python-version: '3.12'
toxenv: py312-fuse3
- os: macos-12
python-version: '3.8'
toxenv: py38-none # note: no fuse testing, due to #6099, see also #6196.
env:
# Configure pkg-config to use OpenSSL from Homebrew
PKG_CONFIG_PATH: "/usr/local/opt/openssl@1.1/lib/pkgconfig:$PKG_CONFIG_PATH"
TOXENV: ${{ matrix.toxenv }}
runs-on: ${{ matrix.os }}
# macOS machines can be slow, if overloaded.
timeout-minutes: 360
timeout-minutes: 90
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v3
with:
# Just fetching one commit is not enough for setuptools-scm, so we fetch all.
# just fetching 1 commit is not enough for setuptools-scm, so we fetch all
fetch-depth: 0
fetch-tags: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Cache pip
uses: actions/cache@v5
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-${{ runner.arch }}-pip-${{ hashFiles('requirements.d/development.lock.txt') }}
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.d/development.txt') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-pip-
${{ runner.os }}-${{ runner.arch }}-
- name: Cache tox environments
uses: actions/cache@v5
with:
path: .tox
key: ${{ runner.os }}-${{ runner.arch }}-tox-${{ matrix.toxenv }}-${{ hashFiles('requirements.d/development.lock.txt', 'pyproject.toml') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-tox-${{ matrix.toxenv }}-
${{ runner.os }}-${{ runner.arch }}-tox-
${{ runner.os }}-pip-
${{ runner.os }}-
- name: Install Linux packages
if: ${{ runner.os == 'Linux' }}
run: |
sudo apt-get update
sudo apt-get install -y pkg-config build-essential
sudo apt-get install -y libssl-dev libacl1-dev liblz4-dev
sudo apt-get install -y bash zsh fish # for shell completion tests
sudo apt-get install -y rclone openssh-server curl
if [[ "$TOXENV" == *"llfuse"* ]]; then
sudo apt-get install -y libfuse-dev fuse # Required for Python llfuse module
elif [[ "$TOXENV" == *"pyfuse3"* || "$TOXENV" == *"mfusepy"* ]]; then
sudo apt-get install -y libfuse3-dev fuse3 # Required for Python pyfuse3 module
fi
sudo apt-get install -y libssl-dev libacl1-dev liblz4-dev libzstd-dev pkg-config build-essential
sudo apt-get install -y libxxhash-dev || true
sudo apt-get install -y libb2-dev || true
sudo apt-get install -y libfuse-dev fuse || true # Required for Python llfuse module
sudo apt-get install -y libfuse3-dev fuse3 || true # Required for Python pyfuse3 module
- name: Install macOS packages
if: ${{ runner.os == 'macOS' }}
run: |
brew unlink pkg-config@0.29.2 || true
brew bundle install
- name: Configure OpenSSH SFTP server (test only)
if: ${{ runner.os == 'Linux' && !contains(matrix.toxenv, 'mypy') && !contains(matrix.toxenv, 'docs') }}
run: |
sudo mkdir -p /run/sshd
sudo useradd -m -s /bin/bash sftpuser || true
# Create SSH key for the CI user and authorize it for sftpuser
mkdir -p ~/.ssh
chmod 700 ~/.ssh
test -f ~/.ssh/id_ed25519 || ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_ed25519
sudo mkdir -p /home/sftpuser/.ssh
sudo chmod 700 /home/sftpuser/.ssh
sudo cp ~/.ssh/id_ed25519.pub /home/sftpuser/.ssh/authorized_keys
sudo chown -R sftpuser:sftpuser /home/sftpuser/.ssh
sudo chmod 600 /home/sftpuser/.ssh/authorized_keys
# Allow publickey auth and enable Subsystem sftp
sudo sed -i 's/^#\?PasswordAuthentication .*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PubkeyAuthentication .*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
if ! grep -q '^Subsystem sftp' /etc/ssh/sshd_config; then echo 'Subsystem sftp /usr/lib/openssh/sftp-server' | sudo tee -a /etc/ssh/sshd_config; fi
# Ensure host keys exist to avoid slow generation on first sshd start
sudo ssh-keygen -A
# Start sshd (listen on default 22 inside runner)
sudo /usr/sbin/sshd -D &
# Add host key to known_hosts so paramiko trusts it
ssh-keyscan -H localhost 127.0.0.1 | tee -a ~/.ssh/known_hosts
# Start ssh-agent and add our key so paramiko can use the agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# The rest test starts "borg serve --rest" over ssh as sftpuser, which runs the borg
# under test from the tox venv under $HOME. Allow sftpuser to traverse into the runner
# home so it can reach that borg (the venv dirs/files are created world-r/x by tox/pip).
sudo chmod o+x "$HOME"
# Export SFTP test URL for tox via GITHUB_ENV
echo "BORG_TEST_SFTP_REPO=sftp://sftpuser@localhost:22/borg/sftp-repo" >> $GITHUB_ENV
echo "BORG_TEST_REST_REPO=rest://sftpuser@localhost:22/borg/rest-repo" >> $GITHUB_ENV
- name: Install and configure MinIO S3 server (test only)
if: ${{ runner.os == 'Linux' && !contains(matrix.toxenv, 'mypy') && !contains(matrix.toxenv, 'docs') }}
run: |
set -e
arch=$(uname -m)
case "$arch" in
x86_64|amd64) srv_url=https://dl.min.io/server/minio/release/linux-amd64/minio; cli_url=https://dl.min.io/client/mc/release/linux-amd64/mc ;;
aarch64|arm64) srv_url=https://dl.min.io/server/minio/release/linux-arm64/minio; cli_url=https://dl.min.io/client/mc/release/linux-arm64/mc ;;
*) echo "Unsupported arch: $arch"; exit 1 ;;
esac
curl -fsSL -o /usr/local/bin/minio "$srv_url"
curl -fsSL -o /usr/local/bin/mc "$cli_url"
sudo chmod +x /usr/local/bin/minio /usr/local/bin/mc
export PATH=/usr/local/bin:$PATH
# Start MinIO on :9000 with default credentials (minioadmin/minioadmin)
MINIO_DIR="$GITHUB_WORKSPACE/.minio-data"
MINIO_LOG="$GITHUB_WORKSPACE/.minio.log"
mkdir -p "$MINIO_DIR"
nohup minio server "$MINIO_DIR" --address ":9000" >"$MINIO_LOG" 2>&1 &
# Wait for MinIO port to be ready
for i in $(seq 1 60); do (echo > /dev/tcp/127.0.0.1/9000) >/dev/null 2>&1 && break; sleep 1; done
# Configure client and create bucket
mc alias set local http://127.0.0.1:9000 minioadmin minioadmin
mc mb --ignore-existing local/borg
# Export S3 test URL for tox via GITHUB_ENV
echo "BORG_TEST_S3_REPO=s3:minioadmin:minioadmin@http://127.0.0.1:9000/borg/s3-repo" >> $GITHUB_ENV
brew install pkg-config || brew upgrade pkg-config
brew install zstd || brew upgrade zstd
brew install lz4 || brew upgrade lz4
brew install openssl@1.1 || brew upgrade openssl@1.1
- name: Install Python requirements
run: |
python -m pip install --upgrade pip setuptools wheel
pip install -r requirements.d/development.lock.txt
pip install -r requirements.d/development.txt
- name: Install borgbackup
env:
# we already have that in the global env, but something is broken and overwrites that.
# so, set it here, again.
PKG_CONFIG_PATH: "/usr/local/opt/openssl@1.1/lib/pkgconfig:$PKG_CONFIG_PATH"
run: |
if [[ "$TOXENV" == *"llfuse"* ]]; then
pip install -ve ".[llfuse,cockpit,s3,sftp,rclone]"
elif [[ "$TOXENV" == *"pyfuse3"* ]]; then
pip install -ve ".[pyfuse3,cockpit,s3,sftp,rclone]"
elif [[ "$TOXENV" == *"mfusepy"* ]]; then
pip install -ve ".[mfusepy,cockpit,s3,sftp,rclone]"
else
pip install -ve ".[cockpit,s3,sftp,rclone]"
fi
- name: Build Borg fat binaries (${{ matrix.binary }})
if: ${{ matrix.binary && startsWith(github.ref, 'refs/tags/') }}
run: |
pip install -r requirements.d/pyinstaller.txt
./scripts/build-borg-using-pyinstaller.sh
- name: Smoke-test the built binary (${{ matrix.binary }})
if: ${{ matrix.binary && startsWith(github.ref, 'refs/tags/') }}
run: |
pushd dist/binary
echo "single-file binary"
chmod +x borg.exe
./borg.exe -V
echo "single-directory binary"
chmod +x borg-dir/borg.exe
./borg-dir/borg.exe -V
tar czf borg.tgz borg-dir
popd
# Ensure locally built binary in ./dist/binary/borg-dir is found during tests
export PATH="$GITHUB_WORKSPACE/dist/binary/borg-dir:$PATH"
echo "borg.exe binary in PATH"
borg.exe -V
- name: Prepare binaries (${{ matrix.binary }})
if: ${{ matrix.binary && startsWith(github.ref, 'refs/tags/') }}
run: |
mkdir -p artifacts
if [ -f dist/binary/borg.exe ]; then
cp dist/binary/borg.exe artifacts/${{ matrix.binary }}
fi
if [ -f dist/binary/borg.tgz ]; then
cp dist/binary/borg.tgz artifacts/${{ matrix.binary }}.tgz
fi
echo "binary files"
ls -l artifacts/
- name: Attest binaries provenance (${{ matrix.binary }})
if: ${{ matrix.binary && startsWith(github.ref, 'refs/tags/') }}
uses: actions/attest-build-provenance@v4
with:
subject-path: 'artifacts/*'
- name: Upload binaries (${{ matrix.binary }})
if: ${{ matrix.binary && startsWith(github.ref, 'refs/tags/') }}
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.binary }}
path: artifacts/*
if-no-files-found: error
- name: run tox env
# pip install -e .
python setup.py -v develop
- name: run pytest via tox
env:
# we already have that in the global env, but something is broken and overwrites that.
# so, set it here, again.
PKG_CONFIG_PATH: "/usr/local/opt/openssl@1.1/lib/pkgconfig:$PKG_CONFIG_PATH"
run: |
# do not use fakeroot, but run as root. avoids the dreaded EISDIR sporadic failures. see #2482.
#sudo -E bash -c "tox -e py"
# Ensure locally built binary in ./dist/binary/borg-dir is found during tests
export PATH="$GITHUB_WORKSPACE/dist/binary/borg-dir:$PATH"
tox --skip-missing-interpreters
- name: Upload test results to Codecov
if: ${{ !cancelled() && !contains(matrix.toxenv, 'mypy') && !contains(matrix.toxenv, 'docs') }}
uses: codecov/codecov-action@v7
env:
OS: ${{ runner.os }}
python: ${{ matrix.python-version }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
env_vars: OS,python
files: test-results.xml
- name: Upload coverage to Codecov
if: ${{ !cancelled() && !contains(matrix.toxenv, 'mypy') && !contains(matrix.toxenv, 'docs') }}
uses: codecov/codecov-action@v7
uses: codecov/codecov-action@v1
env:
OS: ${{ runner.os }}
python: ${{ matrix.python-version }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: coverage
env_vars: OS,python
files: coverage.xml
vm_tests:
permissions:
contents: read
id-token: write
attestations: write
runs-on: ubuntu-24.04
timeout-minutes: 180
needs: [lint]
continue-on-error: true
strategy:
fail-fast: false
matrix:
include:
- os: freebsd
version: '14.3'
display_name: FreeBSD
# Controls binary build and provenance attestation on tags
do_binaries: true
artifact_prefix: borg-freebsd-14-x86_64-gh
- os: netbsd
version: '10.1'
display_name: NetBSD
do_binaries: false
- os: openbsd
version: '7.8'
display_name: OpenBSD
do_binaries: false
- os: omnios
version: 'r151056'
display_name: OmniOS
do_binaries: false
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- name: Test on ${{ matrix.display_name }}
id: cross_os
uses: cross-platform-actions/action@v1.2.0
env:
DO_BINARIES: ${{ matrix.do_binaries }}
with:
operating_system: ${{ matrix.os }}
version: ${{ matrix.version }}
shell: bash
run: |
set -euxo pipefail
case "${{ matrix.os }}" in
freebsd)
export IGNORE_OSVERSION=yes
sudo -E pkg update -f
sudo -E pkg install -y liblz4 pkgconf
sudo -E pkg install -y fusefs-libs
sudo -E kldload fusefs
sudo -E sysctl vfs.usermount=1
sudo -E chmod 666 /dev/fuse
sudo -E pkg install -y rust
sudo -E pkg install -y gmake
sudo -E pkg install -y git
sudo -E pkg install -y python311 py311-sqlite3 py311-pip py311-virtualenv
sudo ln -sf /usr/local/bin/python3.11 /usr/local/bin/python3
sudo ln -sf /usr/local/bin/python3.11 /usr/local/bin/python
sudo ln -sf /usr/local/bin/pip3.11 /usr/local/bin/pip3
sudo ln -sf /usr/local/bin/pip3.11 /usr/local/bin/pip
# required for libsodium/pynacl build
export MAKE=gmake
python -m venv .venv
. .venv/bin/activate
python -V
pip -V
python -m pip install --upgrade pip wheel
pip install -r requirements.d/development.lock.txt
pip install -e ".[mfusepy,cockpit,s3,sftp,rclone]"
tox -e py311-mfusepy
if [[ "${{ matrix.do_binaries }}" == "true" && "${{ startsWith(github.ref, 'refs/tags/') }}" == "true" ]]; then
python -m pip install -r requirements.d/pyinstaller.txt
./scripts/build-borg-using-pyinstaller.sh
pushd dist/binary
echo "single-file binary"
chmod +x borg.exe
./borg.exe -V
echo "single-directory binary"
chmod +x borg-dir/borg.exe
./borg-dir/borg.exe -V
tar czf borg.tgz borg-dir
popd
mkdir -p artifacts
if [ -f dist/binary/borg.exe ]; then
cp -v dist/binary/borg.exe artifacts/${{ matrix.artifact_prefix }}
fi
if [ -f dist/binary/borg.tgz ]; then
cp -v dist/binary/borg.tgz artifacts/${{ matrix.artifact_prefix }}.tgz
fi
fi
;;
netbsd)
arch="$(uname -m)"
sudo -E mkdir -p /usr/pkg/etc/pkgin
echo "https://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/${arch}/10.1/All" | sudo tee /usr/pkg/etc/pkgin/repositories.conf > /dev/null
sudo -E pkgin update
sudo -E pkgin -y upgrade
sudo -E pkgin -y install lz4 git
sudo -E pkgin -y install rust
sudo -E pkgin -y install pkg-config
sudo -E pkgin -y install py311-pip py311-virtualenv py311-tox
sudo -E ln -sf /usr/pkg/bin/python3.11 /usr/pkg/bin/python3
sudo -E ln -sf /usr/pkg/bin/pip3.11 /usr/pkg/bin/pip3
sudo -E ln -sf /usr/pkg/bin/virtualenv-3.11 /usr/pkg/bin/virtualenv3
sudo -E ln -sf /usr/pkg/bin/tox-3.11 /usr/pkg/bin/tox3
# Ensure base system admin tools are on PATH for the non-root shell
export PATH="/sbin:/usr/sbin:$PATH"
echo "--- Preparing an extattr-enabled filesystem ---"
# On many NetBSD setups /tmp is tmpfs without extended attributes.
# Create a FFS image with extended attributes enabled and use it for TMPDIR.
VNDDEV="vnd0"
IMGFILE="/tmp/fs.img"
sudo -E dd if=/dev/zero of=${IMGFILE} bs=1m count=1024
sudo -E vndconfig -c "${VNDDEV}" "${IMGFILE}"
sudo -E newfs -O 2ea /dev/r${VNDDEV}a
MNT="/mnt/eafs"
sudo -E mkdir -p ${MNT}
sudo -E mount -t ffs -o extattr /dev/${VNDDEV}a $MNT
export TMPDIR="${MNT}/tmp"
sudo -E mkdir -p ${TMPDIR}
sudo -E chmod 1777 ${TMPDIR}
touch ${TMPDIR}/testfile
lsextattr user ${TMPDIR}/testfile && echo "[xattr] *** xattrs SUPPORTED on ${TMPDIR}! ***"
tox3 -e py311-none
;;
openbsd)
sudo -E pkg_add lz4 git
sudo -E pkg_add rust
sudo -E pkg_add openssl%3.5
sudo -E pkg_add py3-pip py3-virtualenv py3-tox
export BORG_OPENSSL_NAME=eopenssl35
tox -e py312-none
;;
omnios)
sudo pkg install gcc14 git pkg-config python-313 gnu-make gnu-coreutils rust
sudo ln -sf /usr/bin/python3.13 /usr/bin/python3
sudo ln -sf /usr/bin/python3.13-config /usr/bin/python3-config
sudo python3 -m ensurepip
sudo python3 -m pip install virtualenv
# On omniOS /tmp is swap-backed tmpfs (small, RAM-bound), so the pip/cargo
# build temps and the pytest temp tree quickly exhaust it ("no space left on
# device"). /var/tmp is disk-backed (ZFS), so redirect TMPDIR there.
export TMPDIR=/var/tmp/borg-ci
mkdir -p "$TMPDIR"
python3 -m venv .venv
. .venv/bin/activate
python -V
pip -V
python -m pip install --upgrade pip wheel
pip install -r requirements.d/development.lock.txt
# no fuse support on omnios in our tests usually
pip install -e .
tox -e py313-none
;;
haiku)
pkgman refresh
pkgman install -y git pkgconfig lz4
pkgman install -y openssl3
pkgman install -y rust_bin
pkgman install -y python3.11
pkgman install -y cffi
pkgman install -y lz4_devel openssl3_devel libffi_devel
# there is no pkgman package for tox, so we install it into a venv
python3 -m ensurepip --upgrade
python3 -m pip install --upgrade pip wheel
python3 -m venv .venv
. .venv/bin/activate
export PKG_CONFIG_PATH="/system/develop/lib/pkgconfig:/system/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
export BORG_LIBLZ4_PREFIX=/system/develop
export BORG_OPENSSL_PREFIX=/system/develop
pip install -r requirements.d/development.lock.txt
pip install -e .
# troubles with either tox or pytest xdist, so we run pytest manually:
pytest -v -n auto -rs --cov=borg --cov-config=pyproject.toml --cov-report=xml --junitxml=test-results.xml --benchmark-skip -k "not remote and not socket"
;;
esac
- name: Upload artifacts
if: startsWith(github.ref, 'refs/tags/') && matrix.do_binaries
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact_prefix }}
path: artifacts/*
if-no-files-found: ignore
- name: Attest provenance
if: startsWith(github.ref, 'refs/tags/') && matrix.do_binaries
uses: actions/attest-build-provenance@v4
with:
subject-path: 'artifacts/*'
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v7
env:
OS: ${{ matrix.os }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
env_vars: OS
files: test-results.xml
- name: Upload coverage to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v7
env:
OS: ${{ matrix.os }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: coverage
env_vars: OS
files: coverage.xml
windows_tests:
if: true # can be used to temporarily disable the build
runs-on: windows-latest
timeout-minutes: 90
needs: [lint]
env:
PY_COLORS: 1
MSYS2_ARG_CONV_EXCL: "*"
MSYS2_ENV_CONV_EXCL: "*"
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
- name: Install system packages
run: ./scripts/msys2-install-deps development
- name: Build python venv
run: |
# building cffi / argon2-cffi in the venv fails, so we try to use the system packages
python -m venv --system-site-packages env
. env/bin/activate
# python -m pip install --upgrade pip
# pip install --upgrade setuptools build wheel
pip install -r requirements.d/pyinstaller.txt
- name: Build
run: |
# build borg.exe
. env/bin/activate
pip install -e ".[cockpit,s3,sftp,rclone]"
./scripts/build-borg-using-pyinstaller.sh
# build sdist and wheel in dist/...
python -m build
- uses: actions/upload-artifact@v7
with:
name: borg-windows
path: dist/binary/borg.exe
- name: Run tests
run: |
# Ensure locally built binary in ./dist/binary/borg-dir is found during tests
export PATH="$GITHUB_WORKSPACE/dist/binary/borg-dir:$PATH"
borg.exe -V
. env/bin/activate
python -m pytest -n4 --benchmark-skip -vv -rs -k "not remote" --cov=borg --cov-config=pyproject.toml --cov-report=xml --junitxml=test-results.xml
- name: Upload test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v7
env:
OS: ${{ runner.os }}
python: '3.11'
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: test_results
env_vars: OS,python
files: test-results.xml
- name: Upload coverage to Codecov
if: ${{ !cancelled() }}
uses: codecov/codecov-action@v7
env:
OS: ${{ runner.os }}
python: '3.11'
with:
token: ${{ secrets.CODECOV_TOKEN }}
report_type: coverage
env_vars: OS,python
files: coverage.xml
env_vars: OS, python

View file

@ -4,34 +4,17 @@ name: "CodeQL"
on:
push:
branches: [ master ]
paths:
- '**.py'
- '**.pyx'
- '**.c'
- '**.h'
- '.github/workflows/codeql-analysis.yml'
branches: [ 1.2-maint ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
paths:
- '**.py'
- '**.pyx'
- '**.c'
- '**.h'
- '.github/workflows/codeql-analysis.yml'
branches: [ 1.2-maint ]
schedule:
- cron: '39 2 * * 5'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
analyze:
name: Analyze
runs-on: ubuntu-24.04
timeout-minutes: 20
runs-on: ubuntu-20.04
permissions:
actions: read
contents: read
@ -42,20 +25,20 @@ jobs:
matrix:
language: [ 'cpp', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v3
with:
# Just fetching one commit is not enough for setuptools-scm, so we fetch all.
# just fetching 1 commit is not enough for setuptools-scm, so we fetch all
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v4
with:
python-version: 3.11
python-version: 3.8
- name: Cache pip
uses: actions/cache@v5
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.d/development.txt') }}
@ -66,10 +49,10 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y pkg-config build-essential
sudo apt-get install -y libssl-dev libacl1-dev liblz4-dev
sudo apt-get install -y libssl-dev libacl1-dev libxxhash-dev liblz4-dev libzstd-dev
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -81,6 +64,6 @@ jobs:
python3 -m venv ../borg-env
source ../borg-env/bin/activate
pip3 install -r requirements.d/development.txt
pip3 install -ve .
pip3 install -e .
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v2

27
.github/workflows/windows.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Windows CI
on: [push, pull_request]
jobs:
msys2-ucrt64:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
- name: Install dependencies
run: ./scripts/msys2-install-deps
- name: Build
run: ./scripts/msys2-build
- name: Test
run: ./dist/borg.exe -V
- uses: actions/upload-artifact@v3
with:
name: borg-windows
path: dist/borg.exe

19
.gitignore vendored
View file

@ -2,18 +2,17 @@ MANIFEST
docs/_build
build
dist
external
borg-env
.tox
src/borg/compress.c
src/borg/hashindex.c
src/borg/crypto/low_level.c
src/borg/hashindex.c
src/borg/item.c
src/borg/chunkers/buzhash.c
src/borg/chunkers/buzhash64.c
src/borg/chunkers/reader.c
src/borg/checksums.c
src/borg/chunker.c
src/borg/algorithms/checksums.c
src/borg/platform/darwin.c
src/borg/platform/freebsd.c
src/borg/platform/netbsd.c
src/borg/platform/linux.c
src/borg/platform/syncfilerange.c
src/borg/platform/posix.c
@ -24,12 +23,12 @@ src/borg/_version.py
*.pyd
*.so
.idea/
.junie/
.cache/
.vscode/
borg.build/
borg.dist/
borg.exe
.coverage
.coverage.*
coverage.xml
test-results.xml
.vagrant
.DS_Store
.eggs

View file

@ -1,9 +1,6 @@
repos:
- repo: https://github.com/psf/black
rev: 24.8.0
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.0
hooks:
- id: ruff
- id: flake8
files: '(src|scripts|conftest.py)'

View file

@ -16,6 +16,8 @@ build:
- libacl1-dev
- libssl-dev
- liblz4-dev
- libzstd-dev
- libxxhash-dev
python:
install:
@ -29,4 +31,3 @@ sphinx:
formats:
- htmlzip
- pdf

28
AUTHORS
View file

@ -1,5 +1,5 @@
Email addresses listed here are not intended for support.
Please see the `support section`_ instead.
E-mail addresses listed here are not intended for support, please see
the `support section`_ instead.
.. _support section: https://borgbackup.readthedocs.io/en/stable/support.html
@ -44,3 +44,27 @@ Attic Patches and Suggestions
- Johann Klähn
- Petros Moisiadis
- Thomas Waldmann
BLAKE2
------
Borg includes BLAKE2: Copyright 2012, Samuel Neves <sneves@dei.uc.pt>, licensed under the terms
of the CC0, the OpenSSL Licence, or the Apache Public License 2.0.
Slicing CRC32
-------------
Borg includes a fast slice-by-8 implementation of CRC32, Copyright 2011-2015 Stephan Brumme,
licensed under the terms of a zlib license. See http://create.stephan-brumme.com/crc32/
Folding CRC32
-------------
Borg includes an extremely fast folding implementation of CRC32, Copyright 2013 Intel Corporation,
licensed under the terms of the zlib license.
xxHash
------
XXH64, a fast non-cryptographic hash algorithm. Copyright 2012-2016 Yann Collet,
licensed under a BSD 2-clause license.

View file

@ -1,10 +0,0 @@
brew 'pkgconf'
brew 'lz4'
brew 'openssl@3'
# osxfuse (aka macFUSE) is only required for "borg mount",
# but won't work on GitHub Actions' workers.
# It requires installing a kernel extension, so some users
# may want it and some won't.
#cask 'osxfuse'

View file

@ -1,65 +0,0 @@
# Contributing to BorgBackup
First of all, thank you for considering contributing to Borg!
This guide provides a brief overview of how to contribute.
For the full, detailed development documentation, please refer to the
[Development Docs](https://borgbackup.readthedocs.io/en/master/development.html).
## How to Contribute
1. **Discuss Changes:** Before starting major work, please discuss your proposed changes on the [GitHub issue tracker](https://github.com/borgbackup/borg/issues). Smaller changes can also be discussed in the comments of the pull request.
2. **Branching Model:** Most Pull Requests should be made against the `master` branch. Maintenance branches (e.g., `1.4-maint`) are generally reserved for bug fixes and smaller changes.
3. **Pull Requests:**
- Create a feature branch for your changes.
- Keep changesets clean and focused on a single topic.
- Reference any related issues in your commit messages.
- Ensure your PR includes tests and documentation for new features.
- Proof read your PR yourself, fix typos and other obvious issues.
## Responsible AI Usage
You are welcome to use AI tools, but we require that a human is always "in the loop".
AI-generated content must not be submitted without active critical review, modification, and integration by the human contributor. We require that the final contribution is a product of human creative control and that AI is only used as a supportive tool to assist the human author.
As the contributor, you are responsible for the entire content of your pull request.
This includes:
- Verifying the correctness and security of any AI-generated code.
- Ensuring that new or modified code is covered by correct tests.
- Proofreading and refining any AI-generated documentation or comments.
- Being able to explain, debug, and maintain the code you submit.
Always be aware of the limitations and the ecological footprint of AI tools and act accordingly:
- Do not just believe what AI tells you, but verify it critically. AI is known to hallucinate, to be over-confident and to always tell you that you are right, even when you are not.
- Do not use AI tools for tasks that can be done more efficiently manually or by simpler tools.
- Learn how to use AI tools efficiently.
## Development Setup
Borg is written in Python with some Cython/C. To set up a development environment:
1. Create and activate a virtual environment.
2. Install development dependencies: `pip install -r requirements.d/development.lock.txt`
3. Install borg in editable mode: `pip install -e .`
4. Install pre-commit hooks: `pre-commit install`
## Code Style
We use [Black](https://black.readthedocs.io/) for automated code formatting.
- Install black: `pip install -r requirements.d/codestyle.txt`
- Check formatting: `black --check .`
- Apply formatting: `black .`
## Running Tests
We use `tox` and `pytest` for testing.
- Run all tests: `tox`
For more advanced testing options (including Vagrant and Podman), see the full [Development documentation](https://borgbackup.readthedocs.io/en/master/development.html).
## Security
If you discover a security vulnerability, please follow our [Security Policy](SECURITY.md) for reporting it.

View file

@ -1,4 +1,4 @@
Copyright (C) 2015-2026 The Borg Collective (see AUTHORS file)
Copyright (C) 2015-2023 The Borg Collective (see AUTHORS file)
Copyright (C) 2010-2014 Jonas Borgström <jonas@borgstrom.se>
All rights reserved.

View file

@ -1,6 +1,6 @@
# The files we need to include in the sdist are handled automatically by
# stuff we need to include into the sdist is handled automatically by
# setuptools_scm - it includes all git-committed files.
# But we want to exclude some committed files/directories not needed in the sdist:
# but we want to exclude some committed files/dirs not needed in the sdist:
exclude .editorconfig .gitattributes .gitignore .mailmap Vagrantfile
prune .github
include src/borg/platform/darwin.c src/borg/platform/freebsd.c src/borg/platform/linux.c src/borg/platform/posix.c

View file

@ -1,23 +1,6 @@
This is borg2!
--------------
Please note that this is the README for borg2 / master branch.
For the stable version's docs, please see here:
https://borgbackup.readthedocs.io/en/stable/
Borg2 is currently in beta testing and might get major and/or
breaking changes between beta releases (and there is no beta to
next-beta upgrade code, so you will have to delete and re-create repos).
Thus, **DO NOT USE BORG2 FOR YOUR PRODUCTION BACKUPS!** Please help with
testing it, but set it up *additionally* to your production backups.
TODO: the screencasts need a remake using borg2, see here:
https://github.com/borgbackup/borg/issues/6303
|screencast_basic|
More screencasts: `installation`_, `advanced usage`_
What is BorgBackup?
-------------------
@ -25,17 +8,17 @@ What is BorgBackup?
BorgBackup (short: Borg) is a deduplicating backup program.
Optionally, it supports compression and authenticated encryption.
The main goal of Borg is to provide an efficient and secure way to back up data.
The main goal of Borg is to provide an efficient and secure way to backup data.
The data deduplication technique used makes Borg suitable for daily backups
since only changes are stored.
The authenticated encryption technique makes it suitable for backups to targets not
fully trusted.
The authenticated encryption technique makes it suitable for backups to not
fully trusted targets.
See the `installation manual`_ or, if you have already
downloaded Borg, ``docs/installation.rst`` to get started with Borg.
There is also an `offline documentation`_ available, in multiple formats.
.. _installation manual: https://borgbackup.readthedocs.io/en/master/installation.html
.. _installation manual: https://borgbackup.readthedocs.org/en/stable/installation.html
.. _offline documentation: https://readthedocs.org/projects/borgbackup/downloads
Main features
@ -69,16 +52,15 @@ Main features
**Speed**
* performance-critical code (chunking, compression, encryption) is
implemented in C/Cython
* local caching
* local caching of files/chunks index data
* quick detection of unmodified files
**Data encryption**
All data can be protected client-side using 256-bit authenticated encryption
(AES-OCB or chacha20-poly1305), ensuring data confidentiality, integrity and
authenticity.
All data can be protected using 256-bit AES encryption, data integrity and
authenticity is verified using HMAC-SHA256. Data is encrypted clientside.
**Obfuscation**
Optionally, Borg can actively obfuscate, e.g., the size of files/chunks to
Optionally, borg can actively obfuscate e.g. the size of files / chunks to
make fingerprinting attacks more difficult.
**Compression**
@ -91,24 +73,24 @@ Main features
* lzma (low speed, high compression)
**Off-site backups**
Borg can store data on any remote host accessible over SSH. If Borg is
installed on the remote host, significant performance gains can be achieved
compared to using a network file system (sshfs, NFS, ...).
Borg can store data on any remote host accessible over SSH. If Borg is
installed on the remote host, big performance gains can be achieved
compared to using a network filesystem (sshfs, nfs, ...).
**Backups mountable as file systems**
Backup archives are mountable as user-space file systems for easy interactive
backup examination and restores (e.g., by using a regular file manager).
**Backups mountable as filesystems**
Backup archives are mountable as userspace filesystems for easy interactive
backup examination and restores (e.g. by using a regular file manager).
**Easy installation on multiple platforms**
We offer single-file binaries that do not require installing anything -
you can just run them on these platforms:
* Linux
* macOS
* Mac OS X
* FreeBSD
* OpenBSD and NetBSD (no xattrs/ACLs support or binaries yet)
* Cygwin (experimental, no binaries yet)
* Windows Subsystem for Linux (WSL) on Windows 10/11 (experimental)
* Linux Subsystem of Windows 10 (experimental)
**Free and Open Source Software**
* security and functionality can be audited independently
@ -118,57 +100,61 @@ Main features
Easy to use
~~~~~~~~~~~
For ease of use, set the BORG_REPO environment variable::
Initialize a new backup repository (see ``borg init --help`` for encryption options)::
$ export BORG_REPO=/path/to/repo
$ borg init -e repokey /path/to/repo
Create a new backup repository (see ``borg repo-create --help`` for encryption options)::
Create a backup archive::
$ borg repo-create -e repokey-aes-ocb
$ borg create /path/to/repo::Saturday1 ~/Documents
Create a new backup archive::
Now doing another backup, just to show off the great deduplication::
$ borg create Monday1 ~/Documents
$ borg create -v --stats /path/to/repo::Saturday2 ~/Documents
-----------------------------------------------------------------------------
Archive name: Saturday2
Archive fingerprint: 622b7c53c...
Time (start): Sat, 2016-02-27 14:48:13
Time (end): Sat, 2016-02-27 14:48:14
Duration: 0.88 seconds
Number of files: 163
-----------------------------------------------------------------------------
Original size Compressed size Deduplicated size
This archive: 6.85 MB 6.85 MB 30.79 kB <-- !
All archives: 13.69 MB 13.71 MB 6.88 MB
Now do another backup, just to show off the great deduplication::
$ borg create -v --stats Monday2 ~/Documents
Repository: /path/to/repo
Archive name: Monday2
Archive fingerprint: 7714aef97c1a24539cc3dc73f79b060f14af04e2541da33d54c7ee8e81a00089
Time (start): Mon, 2022-10-03 19:57:35 +0200
Time (end): Mon, 2022-10-03 19:57:35 +0200
Duration: 0.01 seconds
Number of files: 24
Original size: 29.73 MB
Deduplicated size: 520 B
Unique chunks Total chunks
Chunk index: 167 330
-----------------------------------------------------------------------------
Helping, donations and bounties, becoming a Patron
For a graphical frontend refer to our complementary project `BorgWeb <https://borgweb.readthedocs.io/>`_.
Helping, Donations and Bounties, becoming a Patron
--------------------------------------------------
Your help is always welcome!
Spread the word, give feedback, help with documentation, testing or development.
You can also give monetary support to the project, see here for details:
You can also give monetary support to the project, see there for details:
https://www.borgbackup.org/support/fund.html
Links
-----
* `Main website <https://borgbackup.readthedocs.io/>`_
* `Main Web Site <https://borgbackup.readthedocs.org/>`_
* `Releases <https://github.com/borgbackup/borg/releases>`_,
`PyPI packages <https://pypi.org/project/borgbackup/>`_ and
`Changelog <https://github.com/borgbackup/borg/blob/master/docs/changes.rst>`_
* `Offline documentation <https://readthedocs.org/projects/borgbackup/downloads>`_
`PyPI packages <https://pypi.python.org/pypi/borgbackup>`_ and
`ChangeLog <https://github.com/borgbackup/borg/blob/master/docs/changes.rst>`_
* `Offline Documentation <https://readthedocs.org/projects/borgbackup/downloads>`_
* `GitHub <https://github.com/borgbackup/borg>`_ and
`Issue tracker <https://github.com/borgbackup/borg/issues>`_.
* `Web chat (IRC) <https://web.libera.chat/#borgbackup>`_ and
`Mailing list <https://mail.python.org/mailman/listinfo/borgbackup>`_
* `License <https://borgbackup.readthedocs.io/en/master/authors.html#license>`_
* `Security contact <https://borgbackup.readthedocs.io/en/master/support.html#security-contact>`_
`Issue Tracker <https://github.com/borgbackup/borg/issues>`_.
* `Web-Chat (IRC) <https://web.libera.chat/#borgbackup>`_ and
`Mailing List <https://mail.python.org/mailman/listinfo/borgbackup>`_
* `License <https://borgbackup.readthedocs.org/en/stable/authors.html#license>`_
* `Security contact <https://borgbackup.readthedocs.io/en/latest/support.html#security-contact>`_
Compatibility notes
-------------------
@ -178,7 +164,7 @@ CHANGES (like when going from 0.x.y to 1.0.0 or from 1.x.y to 2.0.0).
NOT RELEASED DEVELOPMENT VERSIONS HAVE UNKNOWN COMPATIBILITY PROPERTIES.
THIS IS SOFTWARE IN DEVELOPMENT, DECIDE FOR YOURSELF WHETHER IT FITS YOUR NEEDS.
THIS IS SOFTWARE IN DEVELOPMENT, DECIDE YOURSELF WHETHER IT FITS YOUR NEEDS.
Security issues should be reported to the `Security contact`_ (or
see ``docs/support.rst`` in the source distribution).
@ -187,9 +173,9 @@ see ``docs/support.rst`` in the source distribution).
|doc| |build| |coverage| |bestpractices|
.. |doc| image:: https://readthedocs.org/projects/borgbackup/badge/?version=master
.. |doc| image:: https://readthedocs.org/projects/borgbackup/badge/?version=stable
:alt: Documentation
:target: https://borgbackup.readthedocs.io/en/master/
:target: https://borgbackup.readthedocs.org/en/stable/
.. |build| image:: https://github.com/borgbackup/borg/workflows/CI/badge.svg?branch=master
:alt: Build Status (master)

48
README_WINDOWS.rst Normal file
View file

@ -0,0 +1,48 @@
Borg Native on Windows
======================
Running borg natively on windows is in a early alpha stage. Expect many things to fail.
Do not use the native windows build on any data which you do not want to lose!
Build Requirements
------------------
- VC 14.0 Compiler
- OpenSSL Library v1.1.1c, 64bit (available at https://github.com/python/cpython-bin-deps)
Please use the `win-download-openssl.ps1` script to download and extract the library to
the correct location. See also the OpenSSL section below.
- Patience and a lot of coffee / beer
What's working
--------------
.. note::
The following examples assume that the `BORG_REPO` and `BORG_PASSPHRASE` environment variables are set
if the repo or passphrase is not explicitly given.
- Borg does not crash if called with ``borg``
- ``borg init --encryption repokey-blake2 ./demoRepo`` runs without an error/warning.
Note that absolute paths only work if the protocol is explicitly set to file://
- ``borg create ::backup-{now} D:\DemoData`` works as expected.
- ``borg list`` works as expected.
- ``borg extract --strip-components 1 ::backup-XXXX`` works.
If absolute paths are extracted, it's important to pass ``--strip-components 1`` as
otherwise the data is restored to the original location!
What's NOT working
------------------
- Extracting a backup which was created on windows machine on a non windows machine will fail.
- And many things more.
OpenSSL, Windows and Python
---------------------------
Windows does not ship OpenSSL by default, so we need to get the library from somewhere else.
However, a default python installation does include `libcrypto` which is required by borg.
The only things which are missing to build borg are the header and `*.lib` files.
Luckily the python developers provide all required files in a separate repository.
The `win-download-openssl.ps1` script can be used to download the package from
https://github.com/python/cpython-bin-deps and extract the files to the correct location.
For Anaconda, the required libraries can be installed with `conda install -c anaconda openssl`.

View file

@ -2,18 +2,16 @@
## Supported Versions
These Borg releases are currently supported with security updates.
These borg releases are currently supported with security updates.
| Version | Supported |
|---------|--------------------|
| 2.0.x | :x: (beta) |
| 1.4.x | :white_check_mark: |
| 1.2.x | :x: (no new releases, critical fixes may still be backported) |
| 1.2.x | :white_check_mark: |
| 1.1.x | :x: |
| < 1.1 | :x: |
## Reporting a Vulnerability
See here:
See there:
https://borgbackup.readthedocs.io/en/latest/support.html#security-contact

314
Vagrantfile vendored
View file

@ -1,10 +1,10 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Automated creation of testing environments/binaries on miscellaneous platforms
# Automated creation of testing environments / binaries on misc. platforms
$cpus = Integer(ENV.fetch('VMCPUS', '8')) # create VMs with that many cpus
$xdistn = Integer(ENV.fetch('XDISTN', '8')) # dispatch tests to that many pytest workers
$cpus = Integer(ENV.fetch('VMCPUS', '16')) # create VMs with that many cpus
$xdistn = Integer(ENV.fetch('XDISTN', '16')) # dispatch tests to that many pytest workers
$wmem = $xdistn * 256 # give the VM additional memory for workers [MB]
def packages_debianoid(user)
@ -15,8 +15,7 @@ def packages_debianoid(user)
apt-get -y -qq update
apt-get -y -qq dist-upgrade
# for building borgbackup and dependencies:
apt install -y pkg-config
apt install -y libssl-dev libacl1-dev liblz4-dev || true
apt install -y libssl-dev libacl1-dev liblz4-dev libzstd-dev pkg-config
apt install -y libfuse-dev fuse || true
apt install -y libfuse3-dev fuse3 || true
apt install -y locales || true
@ -38,16 +37,16 @@ def packages_freebsd
# install all the (security and other) updates, base system
freebsd-update --not-running-from-cron fetch install
# for building borgbackup and dependencies:
pkg install -y liblz4 pkgconf
pkg install -y liblz4 zstd pkgconf
pkg install -y fusefs-libs || true
pkg install -y fusefs-libs3 || true
pkg install -y rust
pkg install -y git bash # fakeroot causes lots of troubles on freebsd
pkg install -y python311 py311-sqlite3 py311-pip py311-virtualenv
# make sure there is a python3/pip3/virtualenv command
ln -sf /usr/local/bin/python3.11 /usr/local/bin/python3
ln -sf /usr/local/bin/pip-3.11 /usr/local/bin/pip3
ln -sf /usr/local/bin/virtualenv-3.11 /usr/local/bin/virtualenv
# for building python (for the tests we use pyenv built pythons):
pkg install -y python38 py38-sqlite3
# make sure there is a python3 command
ln -sf /usr/local/bin/python3.8 /usr/local/bin/python3
python3 -m ensurepip
pip3 install virtualenv
# make bash default / work:
chsh -s bash vagrant
mount -t fdescfs fdesc /dev/fd
@ -64,84 +63,80 @@ def packages_freebsd
pkg update
yes | pkg upgrade
echo 'export BORG_OPENSSL_PREFIX=/usr' >> ~vagrant/.bash_profile
# (re)mount / with acls
mount -o acls /
EOF
end
def packages_openbsd
return <<-EOF
hostname "openbsd77.localdomain"
echo "$(hostname)" > /etc/myname
echo "127.0.0.1 localhost" > /etc/hosts
echo "::1 localhost" >> /etc/hosts
echo "127.0.0.1 $(hostname) $(hostname -s)" >> /etc/hosts
echo "https://ftp.eu.openbsd.org/pub/OpenBSD" > /etc/installurl
ftp https://cdn.openbsd.org/pub/OpenBSD/$(uname -r)/$(uname -m)/comp$(uname -r | tr -d .).tgz
tar -C / -xzphf comp$(uname -r | tr -d .).tgz
rm comp$(uname -r | tr -d .).tgz
pkg_add bash
chsh -s bash vagrant
pkg_add xxhash
pkg_add lz4
pkg_add zstd
pkg_add git # no fakeroot
pkg_add rust
pkg_add openssl%3.4
pkg_add openssl%1.1
pkg_add py3-pip
pkg_add py3-virtualenv
echo 'export BORG_OPENSSL_NAME=eopenssl30' >> ~vagrant/.bash_profile
EOF
end
def packages_netbsd
return <<-EOF
echo 'https://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/$arch/9.3/All' > /usr/pkg/etc/pkgin/repositories.conf
echo 'http://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/$arch/9.3/All' > /usr/pkg/etc/pkgin/repositories.conf
pkgin update
pkgin -y upgrade
pkg_add lz4 git
pkg_add rust
pkg_add zstd lz4 xxhash git
pkg_add bash
chsh -s bash vagrant
echo "export PROMPT_COMMAND=" >> ~vagrant/.bash_profile # bug in netbsd 9.3, .bash_profile broken for screen
echo "export PROMPT_COMMAND=" >> ~root/.bash_profile # bug in netbsd 9.3, .bash_profile broken for screen
echo "export PROMPT_COMMAND=" >> ~vagrant/.bash_profile # bug in netbsd 9.2, .bash_profile broken for screen
echo "export PROMPT_COMMAND=" >> ~root/.bash_profile # bug in netbsd 9.2, .bash_profile broken for screen
pkg_add pkg-config
# pkg_add fuse # llfuse supports netbsd, but is still buggy.
# https://bitbucket.org/nikratio/python-llfuse/issues/70/perfuse_open-setsockopt-no-buffer-space
pkg_add py311-sqlite3 py311-pip py311-virtualenv py311-expat
ln -s /usr/pkg/bin/python3.11 /usr/pkg/bin/python
ln -s /usr/pkg/bin/python3.11 /usr/pkg/bin/python3
ln -s /usr/pkg/bin/pip3.11 /usr/pkg/bin/pip
ln -s /usr/pkg/bin/pip3.11 /usr/pkg/bin/pip3
ln -s /usr/pkg/bin/virtualenv-3.11 /usr/pkg/bin/virtualenv
ln -s /usr/pkg/bin/virtualenv-3.11 /usr/pkg/bin/virtualenv3
pkg_add python38 py38-sqlite3 py38-pip py38-virtualenv py38-expat
pkg_add python39 py39-sqlite3 py39-pip py39-virtualenv py39-expat
pkg_add py310-sqlite3 py310-pip py310-virtualenv py310-expat
ln -s /usr/pkg/bin/python3.9 /usr/pkg/bin/python
ln -s /usr/pkg/bin/python3.9 /usr/pkg/bin/python3
ln -s /usr/pkg/bin/pip3.9 /usr/pkg/bin/pip
ln -s /usr/pkg/bin/pip3.9 /usr/pkg/bin/pip3
ln -s /usr/pkg/bin/virtualenv-3.9 /usr/pkg/bin/virtualenv
ln -s /usr/pkg/bin/virtualenv-3.9 /usr/pkg/bin/virtualenv3
EOF
end
def package_update_openindiana
def packages_darwin
return <<-EOF
echo "nameserver 1.1.1.1" > /etc/resolv.conf
# needs separate provisioning step + reboot to become effective:
pkg update
# install all the (security and other) updates
sudo softwareupdate --ignore iTunesX
sudo softwareupdate --ignore iTunes
sudo softwareupdate --ignore Safari
sudo softwareupdate --ignore "Install macOS High Sierra"
sudo softwareupdate --install --all
which brew || CI=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
brew update > /dev/null
brew install pkg-config readline openssl@1.1 zstd lz4 xz
brew install --cask macfuse
# brew upgrade # upgrade everything (takes rather long)
echo 'export PKG_CONFIG_PATH=/usr/local/opt/openssl@1.1/lib/pkgconfig' >> ~vagrant/.bash_profile
EOF
end
def packages_openindiana
return <<-EOF
pkg install gcc-13 git
pkg install pkg-config
pkg install python-313
ln -sf /usr/bin/python3.13 /usr/bin/python3
ln -sf /usr/bin/python3.13-config /usr/bin/python3-config
# needs separate provisioning step + reboot:
#pkg update
#pkg install gcc-7 python-39 setuptools-39
ln -sf /usr/bin/python3.9 /usr/bin/python3
python3 -m ensurepip
ln -sf /usr/bin/pip3.13 /usr/bin/pip3
ln -sf /usr/bin/pip3.9 /usr/bin/pip3
pip3 install virtualenv
# let borg's pkg-config find openssl:
pfexec pkg set-mediator -V 3 openssl
EOF
end
def install_pyenv(boxname)
return <<-EOF
echo 'export PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS} --enable-shared"' >> ~/.bash_profile
echo 'export PYTHON_CONFIGURE_OPTS="--enable-shared"' >> ~/.bash_profile
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
. ~/.bash_profile
@ -154,11 +149,19 @@ def install_pyenv(boxname)
EOF
end
def fix_pyenv_darwin(boxname)
return <<-EOF
echo 'export PYTHON_CONFIGURE_OPTS="--enable-framework"' >> ~/.bash_profile
EOF
end
def install_pythons(boxname)
return <<-EOF
. ~/.bash_profile
echo "PYTHON_CONFIGURE_OPTS: ${PYTHON_CONFIGURE_OPTS}"
pyenv install 3.13.8
pyenv install 3.12.0 # tests, version supporting openssl 1.1
pyenv install 3.11.1 # tests, version supporting openssl 1.1
pyenv install 3.10.2 # tests, version supporting openssl 1.1
pyenv install 3.9.18 # tests, version supporting openssl 1.1, binary build
pyenv rehash
EOF
end
@ -175,9 +178,9 @@ def build_pyenv_venv(boxname)
return <<-EOF
. ~/.bash_profile
cd /vagrant/borg
# use the latest 3.13 release
pyenv global 3.13.8
pyenv virtualenv 3.13.8 borg-env
# use the latest 3.9 release
pyenv global 3.9.18
pyenv virtualenv 3.9.18 borg-env
ln -s ~/.pyenv/versions/borg-env .
EOF
end
@ -190,10 +193,8 @@ def install_borg(fuse)
pip install -U wheel # upgrade wheel, might be too old
cd borg
pip install -r requirements.d/development.lock.txt
python3 scripts/make.py clean
# install borgstore WITH all options, so it pulls in the needed
# requirements, so they will also get into the binaries built. #8574
pip install borgstore[sftp,s3]
python setup.py clean
python setup.py clean2
pip install -e .[#{fuse}]
EOF
end
@ -203,7 +204,7 @@ def install_pyinstaller()
. ~/.bash_profile
cd /vagrant/borg
. borg-env/bin/activate
pip install -r requirements.d/pyinstaller.txt
pip install 'pyinstaller==4.10'
EOF
end
@ -226,10 +227,12 @@ def run_tests(boxname, skip_env)
. ../borg-env/bin/activate
if which pyenv 2> /dev/null; then
# for testing, use the earliest point releases of the supported python versions:
pyenv global 3.13.8
pyenv local 3.13.8
pyenv global 3.9.18 3.10.2 3.11.1 3.12.0
pyenv local 3.9.18 3.10.2 3.11.1 3.12.0
fi
# otherwise: just use the system python
# avoid that git complains about dubious ownership if we use fakeroot:
git config --global --add safe.directory /vagrant/borg/borg
# some OSes can only run specific test envs, e.g. because they miss FUSE support:
export TOX_SKIP_ENV='#{skip_env}'
if which fakeroot 2> /dev/null; then
@ -268,95 +271,95 @@ Vagrant.configure(2) do |config|
v.cpus = $cpus
end
config.vm.define "noble" do |b|
b.vm.box = "bento/ubuntu-24.04"
config.vm.define "focal64" do |b|
b.vm.box = "ubuntu/focal64"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("noble")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("focal64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("noble", ".*none.*")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("focal64", ".*none.*")
end
config.vm.define "jammy" do |b|
config.vm.define "jammy64" do |b|
b.vm.box = "ubuntu/jammy64"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("jammy")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("jammy64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("jammy", ".*none.*")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("jammy64", ".*none.*")
end
config.vm.define "trixie" do |b|
b.vm.box = "debian/testing64"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("trixie")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("trixie")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("trixie")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("trixie")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("trixie", ".*none.*")
end
config.vm.define "bookworm32" do |b|
b.vm.box = "generic-x32/debian12"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("bookworm32")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("bookworm32")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("bookworm32")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("bookworm32")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("bookworm32", ".*none.*")
end
config.vm.define "bookworm" do |b|
config.vm.define "bookworm64" do |b|
b.vm.box = "debian/bookworm64"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("bookworm")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("bookworm")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("bookworm")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("bookworm64")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("bookworm64")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("bookworm64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("bookworm")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("bookworm", ".*none.*")
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("bookworm64")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("bookworm64", ".*none.*")
end
config.vm.define "bullseye" do |b|
config.vm.define "bullseye64" do |b|
b.vm.box = "debian/bullseye64"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("bullseye")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("bullseye")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("bullseye")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("bullseye64")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("bullseye64")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("bullseye64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("bullseye")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("bullseye", ".*none.*")
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("bullseye64")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("bullseye64", ".*none.*")
end
config.vm.define "freebsd13" do |b|
config.vm.define "buster64" do |b|
b.vm.box = "debian/buster64"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("buster64")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("buster64")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("buster64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("buster64")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("buster64", ".*none.*")
end
config.vm.define "stretch64" do |b|
b.vm.box = "generic/debian9"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages debianoid", :type => :shell, :inline => packages_debianoid("vagrant")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("stretch64")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("stretch64")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("stretch64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("stretch64")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("stretch64", ".*(fuse3|none).*")
end
config.vm.define "freebsd64" do |b|
b.vm.box = "generic/freebsd13"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
@ -364,68 +367,79 @@ Vagrant.configure(2) do |config|
b.ssh.shell = "sh"
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages freebsd", :type => :shell, :inline => packages_freebsd
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("freebsd13")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("freebsd13")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("freebsd13")
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("freebsd64")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("freebsd64")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("freebsd64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("freebsd13")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("freebsd13", ".*(pyfuse3|none).*")
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("freebsd64")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("freebsd64", ".*(fuse3|none).*")
end
config.vm.define "freebsd14" do |b|
b.vm.box = "generic/freebsd14"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.ssh.shell = "sh"
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages freebsd", :type => :shell, :inline => packages_freebsd
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("freebsd14")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("freebsd14")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("freebsd14")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("freebsd14")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("freebsd14", ".*(pyfuse3|none).*")
end
config.vm.define "openbsd7" do |b|
b.vm.box = "l3system/openbsd77-amd64"
config.vm.define "openbsd64" do |b|
b.vm.box = "openbsd71-64"
b.vm.provider :virtualbox do |v|
v.memory = 1024 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages openbsd", :type => :shell, :inline => packages_openbsd
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("openbsd7")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("openbsd64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("nofuse")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("openbsd7", ".*fuse.*")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("openbsd64", ".*fuse.*")
end
config.vm.define "netbsd9" do |b|
config.vm.define "netbsd64" do |b|
b.vm.box = "generic/netbsd9"
b.vm.provider :virtualbox do |v|
v.memory = 4096 + $wmem # need big /tmp tmpfs in RAM!
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages netbsd", :type => :shell, :inline => packages_netbsd
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("netbsd9")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("nofuse")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("netbsd9", ".*fuse.*")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("netbsd64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg(false)
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("netbsd64", ".*fuse.*")
end
config.vm.define "darwin64" do |b|
b.vm.box = "macos-sierra"
b.vm.provider :virtualbox do |v|
v.memory = 4096 + $wmem
v.customize ['modifyvm', :id, '--ostype', 'MacOS_64']
v.customize ['modifyvm', :id, '--paravirtprovider', 'default']
v.customize ['modifyvm', :id, '--nested-hw-virt', 'on']
# Adjust CPU settings according to
# https://github.com/geerlingguy/macos-virtualbox-vm
v.customize ['modifyvm', :id, '--cpuidset',
'00000001', '000306a9', '00020800', '80000201', '178bfbff']
# Disable USB variant requiring Virtualbox proprietary extension pack
v.customize ["modifyvm", :id, '--usbehci', 'off', '--usbxhci', 'off']
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "packages darwin", :type => :shell, :privileged => false, :inline => packages_darwin
b.vm.provision "install pyenv", :type => :shell, :privileged => false, :inline => install_pyenv("darwin64")
b.vm.provision "fix pyenv", :type => :shell, :privileged => false, :inline => fix_pyenv_darwin("darwin64")
b.vm.provision "install pythons", :type => :shell, :privileged => false, :inline => install_pythons("darwin64")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_pyenv_venv("darwin64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("llfuse")
b.vm.provision "install pyinstaller", :type => :shell, :privileged => false, :inline => install_pyinstaller()
b.vm.provision "build binary with pyinstaller", :type => :shell, :privileged => false, :inline => build_binary_with_pyinstaller("darwin64")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("darwin64", ".*(fuse3|none).*")
end
# rsync on openindiana has troubles, does not set correct owner for /vagrant/borg and thus gives lots of
# permission errors. can be manually fixed in the VM by: sudo chown -R vagrant /vagrant/borg ; then rsync again.
config.vm.define "openindiana" do |b|
b.vm.box = "openindiana/hipster"
config.vm.define "openindiana64" do |b|
b.vm.box = "openindiana"
b.vm.provider :virtualbox do |v|
v.memory = 2048 + $wmem
end
b.vm.provision "fs init", :type => :shell, :inline => fs_init("vagrant")
b.vm.provision "package update openindiana", :type => :shell, :inline => package_update_openindiana, :reboot => true
b.vm.provision "packages openindiana", :type => :shell, :inline => packages_openindiana
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("openindiana")
b.vm.provision "build env", :type => :shell, :privileged => false, :inline => build_sys_venv("openindiana64")
b.vm.provision "install borg", :type => :shell, :privileged => false, :inline => install_borg("nofuse")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("openindiana", ".*fuse.*")
b.vm.provision "run tests", :type => :shell, :privileged => false, :inline => run_tests("openindiana64", ".*fuse.*")
end
# TODO: create more VMs with python 3.8+ and openssl 1.1.
# See branch 1.1-maint for a better equipped Vagrantfile (but still on py35 and openssl 1.0).
end

81
conftest.py Normal file
View file

@ -0,0 +1,81 @@
import os
import pytest
# IMPORTANT keep this above all other borg imports to avoid inconsistent values
# for `from borg.constants import PBKDF2_ITERATIONS` (or star import) usages before
# this is executed
from borg import constants
# no fixture-based monkey-patching since star-imports are used for the constants module
constants.PBKDF2_ITERATIONS = 1
# needed to get pretty assertion failures in unit tests:
if hasattr(pytest, 'register_assert_rewrite'):
pytest.register_assert_rewrite('borg.testsuite')
import borg.cache # noqa: E402
from borg.logger import setup_logging # noqa: E402
# Ensure that the loggers exist for all tests
setup_logging()
from borg.testsuite import has_lchflags, has_llfuse, has_pyfuse3 # noqa: E402
from borg.testsuite import are_symlinks_supported, are_hardlinks_supported, is_utime_fully_supported # noqa: E402
from borg.testsuite.platform import fakeroot_detected # noqa: E402
@pytest.fixture(autouse=True)
def clean_env(tmpdir_factory, monkeypatch):
# avoid that we access / modify the user's normal .config / .cache directory:
monkeypatch.setenv('XDG_CONFIG_HOME', str(tmpdir_factory.mktemp('xdg-config-home')))
monkeypatch.setenv('XDG_CACHE_HOME', str(tmpdir_factory.mktemp('xdg-cache-home')))
# also avoid to use anything from the outside environment:
keys = [key for key in os.environ
if key.startswith('BORG_') and key not in ('BORG_FUSE_IMPL', )]
for key in keys:
monkeypatch.delenv(key, raising=False)
def pytest_report_header(config, startdir):
tests = {
"BSD flags": has_lchflags,
"fuse2": has_llfuse,
"fuse3": has_pyfuse3,
"root": not fakeroot_detected(),
"symlinks": are_symlinks_supported(),
"hardlinks": are_hardlinks_supported(),
"atime/mtime": is_utime_fully_supported(),
"modes": "BORG_TESTS_IGNORE_MODES" not in os.environ
}
enabled = []
disabled = []
for test in tests:
if tests[test]:
enabled.append(test)
else:
disabled.append(test)
output = "Tests enabled: " + ", ".join(enabled) + "\n"
output += "Tests disabled: " + ", ".join(disabled)
return output
class DefaultPatches:
def __init__(self, request):
self.org_cache_wipe_cache = borg.cache.LocalCache.wipe_cache
def wipe_should_not_be_called(*a, **kw):
raise AssertionError("Cache wipe was triggered, if this is part of the test add "
"@pytest.mark.allow_cache_wipe")
if 'allow_cache_wipe' not in request.keywords:
borg.cache.LocalCache.wipe_cache = wipe_should_not_be_called
request.addfinalizer(self.undo)
def undo(self):
borg.cache.LocalCache.wipe_cache = self.org_cache_wipe_cache
@pytest.fixture(autouse=True)
def default_patches(request):
return DefaultPatches(request)

View file

@ -1,5 +1,5 @@
Here we store third-party documentation, licenses, etc.
Here we store 3rd party documentation, licenses, etc.
Please note that all files inside the "borg" package directory (except those
excluded in setup.py) will be installed, so do not keep docs or licenses
Please note that all files inside the "borg" package directory (except the
stuff excluded in setup.py) will be INSTALLED, so don't keep docs or licenses
there.

24
docs/3rd_party/lz4/LICENSE vendored Normal file
View file

@ -0,0 +1,24 @@
LZ4 Library
Copyright (c) 2011-2016, Yann Collet
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

30
docs/3rd_party/zstd/LICENSE vendored Normal file
View file

@ -0,0 +1,30 @@
BSD License
For Zstandard software
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -21,7 +21,7 @@ help:
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and an HTML help project"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"

View file

@ -1,27 +0,0 @@
<p class="borg-downloads" id="borg-downloads" style="display:none;">Downloads: <span id="borg-downloads-list"></span></p>
<script type="text/javascript">
// Populate offline download links (PDF, HTMLzip, ...) on a single line using ReadTheDocs data if available.
function borgInitDownloads(data) {
var downloads = data && data.versions && data.versions.current && data.versions.current.downloads;
if (!downloads) return;
var labels = {pdf: "PDF", htmlzip: "HTML", epub: "ePub"};
var span = document.getElementById("borg-downloads-list");
if (!span) return;
var first = true;
Object.keys(downloads).forEach(function(fmt) {
var url = downloads[fmt];
if (!url) return;
if (!first) span.appendChild(document.createTextNode(" | "));
var a = document.createElement("a");
a.href = url;
a.textContent = labels[fmt] || fmt;
span.appendChild(a);
first = false;
});
if (!first) document.getElementById("borg-downloads").style.display = "";
}
document.addEventListener("readthedocs-addons-data-ready", function(event) {
borgInitDownloads(event.detail.data());
});
</script>

View file

@ -1,6 +1,6 @@
<div class="sidebar-block">
<div class="sidebar-toc">
{# Restrict the sidebar ToC depth to two levels while generating command usage pages.
{# Restrict the sidebar toc depth to two levels while generating command usage pages.
This avoids superfluous entries for each "Description" and "Examples" heading. #}
{% if pagename.startswith("usage/") and pagename not in (
"usage/general", "usage/help", "usage/debug", "usage/notes",

View file

@ -1,174 +0,0 @@
{%- extends "basic/layout.html" %}
{# Do this so that Bootstrap is included before the main CSS file. #}
{%- block htmltitle %}
{% set script_files = script_files + ["_static/myscript.js"] %}
<!-- Licensed under the Apache 2.0 License -->
<link rel="stylesheet" type="text/css" href="{{ pathto('_static/fonts/open-sans/stylesheet.css', 1) }}" />
<!-- Licensed under the SIL Open Font License -->
<link rel="stylesheet" type="text/css" href="{{ pathto('_static/fonts/source-serif-pro/source-serif-pro.css', 1) }}" />
<link rel="stylesheet" type="text/css" href="{{ pathto('_static/css/bootstrap.min.css', 1) }}" />
<link rel="stylesheet" type="text/css" href="{{ pathto('_static/css/bootstrap-theme.min.css', 1) }}" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{ super() }}
{%- endblock %}
{%- block extrahead %}
{% if theme_touch_icon %}
<link rel="apple-touch-icon" href="{{ pathto('_static/' ~ theme_touch_icon, 1) }}" />
{% endif %}
<meta name="readthedocs-addons-api-version" content="1" />
{{ super() }}
{% endblock %}
{# Displays the URL for the homepage if it's set, or the master_doc if it is not. #}
{% macro homepage() -%}
{%- if theme_homepage %}
{%- if hasdoc(theme_homepage) %}
{{ pathto(theme_homepage) }}
{%- else %}
{{ theme_homepage }}
{%- endif %}
{%- else %}
{{ pathto(master_doc) }}
{%- endif %}
{%- endmacro %}
{# Displays the URL for the tospage if it's set, or falls back to the homepage macro. #}
{% macro tospage() -%}
{%- if theme_tospage %}
{%- if hasdoc(theme_tospage) %}
{{ pathto(theme_tospage) }}
{%- else %}
{{ theme_tospage }}
{%- endif %}
{%- else %}
{{ homepage() }}
{%- endif %}
{%- endmacro %}
{# Displays the URL for the projectpage if it's set, or falls back to the homepage macro. #}
{% macro projectlink() -%}
{%- if theme_projectlink %}
{%- if hasdoc(theme_projectlink) %}
{{ pathto(theme_projectlink) }}
{%- else %}
{{ theme_projectlink }}
{%- endif %}
{%- else %}
{{ homepage() }}
{%- endif %}
{%- endmacro %}
{# Displays the next and previous links both before and after the content. #}
{% macro render_relations() -%}
{% if prev or next %}
<div class="footer-relations">
{% if prev %}
<div class="pull-left">
<a class="btn btn-default" href="{{ prev.link|e }}" title="{{ _('previous chapter')}} (use the left arrow)">{{ prev.title }}</a>
</div>
{% endif %}
{%- if next and next.title != '&lt;no title&gt;' %}
<div class="pull-right">
<a class="btn btn-default" href="{{ next.link|e }}" title="{{ _('next chapter')}} (use the right arrow)">{{ next.title }}</a>
</div>
{%- endif %}
</div>
<div class="clearer"></div>
{% endif %}
{%- endmacro %}
{%- macro guzzle_sidebar() %}
<div id="left-column">
<div class="sphinxsidebar">
{%- if sidebars != None %}
{#- New-style sidebar: explicitly include/exclude templates. #}
{%- for sidebartemplate in sidebars %}
{%- include sidebartemplate %}
{%- endfor %}
{% else %}
{% include "logo-text.html" %}
{% include "globaltoc.html" %}
{% include "searchbox.html" %}
{%- endif %}
</div>
</div>
{%- endmacro %}
{%- block content %}
{%- if pagename == 'index' and theme_index_template %}
{% include theme_index_template %}
{%- else %}
<div class="container-wrapper">
<div id="mobile-toggle">
<a href="#"><span class="glyphicon glyphicon-align-justify" aria-hidden="true"></span></a>
</div>
{%- block sidebar1 %}{{ guzzle_sidebar() }}{% endblock %}
{%- block document_wrapper %}
{%- block document %}
<div id="right-column">
{% block breadcrumbs %}
<div role="navigation" aria-label="breadcrumbs navigation">
<ol class="breadcrumb">
<li><a href="{{ pathto(master_doc) }}">Docs</a></li>
{% for doc in parents %}
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a></li>
{% endfor %}
<li>{{ title }}</li>
</ol>
</div>
{% endblock %}
<div class="document clearer body" role="main">
{% block body %} {% endblock %}
</div>
{%- block bottom_rel_links %}
{{ render_relations() }}
{%- endblock %}
</div>
<div class="clearfix"></div>
{%- endblock %}
{%- endblock %}
{%- block comments -%}
{% if theme_disqus_comments_shortname %}
<div class="container comment-container">
{% include "comments.html" %}
</div>
{% endif %}
{%- endblock %}
</div>
{%- endif %}
{%- endblock %}
{%- block footer %}
<script type="text/javascript">
$("#mobile-toggle a").click(function () {
$("#left-column").toggle();
});
</script>
<script type="text/javascript" src="{{ pathto('_static/js/bootstrap.js', 1)}}"></script>
{%- block footer_wrapper %}
<div class="footer">
&copy; Copyright {{ copyright }}. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.
</div>
{%- endblock %}
{%- block ga %}
{%- if theme_google_analytics_account %}
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', '{{ theme_google_analytics_account }}']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
{%- endif %}
{%- endblock %}
{%- endblock %}

View file

@ -1,29 +0,0 @@
<div class="version-selector" id="borg-version-selector" style="display:none;">
<label for="version-select">Select your Borg version:</label>
<select id="version-select"></select>
</div>
<script type="text/javascript">
// Populate the version selector using ReadTheDocs data if available.
function borgInitVersionSelector(data) {
var versions = data && data.versions && data.versions.active;
if (!versions || !versions.length) return;
var current = data.versions && data.versions.current && data.versions.current.slug;
var select = document.getElementById("version-select");
if (!select) return;
versions.forEach(function(v) {
var opt = document.createElement("option");
opt.value = v.urls.documentation;
opt.textContent = v.slug;
if (v.slug === current) opt.selected = true;
select.appendChild(opt);
});
select.addEventListener("change", function() {
window.location.href = this.value;
});
document.getElementById("borg-version-selector").style.display = "";
}
document.addEventListener("readthedocs-addons-data-ready", function(event) {
borgInitVersionSelector(event.detail.data());
});
</script>

View file

@ -1,117 +0,0 @@
Binary BorgBackup builds
========================
General notes
-------------
The binaries are supposed to work on the specified platform without installing anything else.
There are some limitations, though:
- for Linux, your system must have the same or newer glibc version as the one used for building
- for macOS, you need to have the same or newer macOS version as the one used for building
- for other OSes, there are likely similar limitations
If you don't find something working on your system, check the older borg releases.
*.asc are GnuPG signatures - only provided for locally built binaries.
*.exe (or no extension) is the single-file fat binary.
*.tgz is the single-directory fat binary (extract it once with tar -xzf).
Using the single-directory build is faster and does not require as much space
in the temporary directory as the self-extracting single-file build.
macOS: to avoid issues, download the file via the command line OR remove the
"quarantine" attribute after downloading:
$ xattr -dr com.apple.quarantine borg-macos1012.tgz
Download the correct files
--------------------------
Binaries built on GitHub servers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
borg-linux-glibc235-x86_64-gh Linux AMD/Intel (built on Ubuntu 22.04 LTS with glibc 2.35)
borg-linux-glibc235-arm64-gh Linux ARM (built on Ubuntu 22.04 LTS with glibc 2.35)
borg-macos-15-arm64-gh macOS Apple Silicon (built on macOS 15 w/o FUSE support)
borg-macos-15-x86_64-gh macOS Intel (built on macOS 15 w/o FUSE support)
borg-freebsd-14-x86_64-gh FreeBSD AMD/Intel (built on FreeBSD 14)
Binaries built locally
~~~~~~~~~~~~~~~~~~~~~~
borg-linux-glibc231-x86_64 Linux (built on Debian 11 "Bullseye" with glibc 2.31)
Note: if you don't find a specific binary here, check release 1.4.1 or 1.2.9.
Verifying your download
-----------------------
I provide GPG signatures for files which I have built locally on my machines.
To check the GPG signature, download both the file and the corresponding
signature (*.asc file) and then (on the shell) type, for example:
gpg --recv-keys 9F88FB52FAF7B393
gpg --verify borgbackup.tar.gz.asc borgbackup.tar.gz
The files are signed by:
Thomas Waldmann <tw@waldmann-edv.de>
GPG key fingerprint: 6D5B EF9A DD20 7580 5747 B70F 9F88 FB52 FAF7 B393
My fingerprint is also in the footer of all my BorgBackup mailing list posts.
Provenance attestations for GitHub-built binaries
-------------------------------------------------
For binaries built on GitHub (files with a "-gh" suffix in the name), we publish
an artifact provenance attestation that proves the binary was built by our
GitHub Actions workflow from a specific commit or tag. You can verify this using
the GitHub CLI (gh). Install it from https://cli.github.com/ and make sure you
use a recent version that supports "gh attestation".
Practical example (Linux, 2.0.0b20 tag):
curl -LO https://github.com/borgbackup/borg/releases/download/2.0.0b20/borg-linux-glibc235-x86_64-gh
gh attestation verify --repo borgbackup/borg --source-ref refs/tags/2.0.0b20 borg-linux-glibc235-x86_64-gh
If verification succeeds, gh prints a summary stating the subject (your file),
that it was attested by GitHub Actions, and the job/workflow reference.
Installing
----------
It is suggested that you rename or symlink the binary to just "borg".
If you need "borgfs", just also symlink it to the same binary; it will
detect internally under which name it was invoked.
On UNIX-like platforms, /usr/local/bin/ or ~/bin/ is a nice place for it,
but you can invoke it from anywhere by providing the full path to it.
Make sure the file is readable and executable (chmod +rx borg on UNIX-like
platforms).
Reporting issues
----------------
Please first check the FAQ and whether a GitHub issue already exists.
If you find a NEW issue, please open a ticket on our issue tracker:
https://github.com/borgbackup/borg/issues/
There, please give:
- the version number (it is displayed if you invoke borg -V)
- the sha256sum of the binary
- a good description of what the issue is
- a good description of how to reproduce your issue
- a traceback with system info (if you have one)
- your precise platform (CPU, 32/64-bit?), OS, distribution, release
- your Python and (g)libc versions

View file

@ -5,8 +5,8 @@
Borg documentation
==================
.. When you add an element here, do not forget to add it to index.rst.
.. Note: Some things are in appendices (see latex_appendices in conf.py).
.. when you add an element here, do not forget to add it to index.rst
.. Note: Some things are in appendices (see latex_appendices in conf.py)
.. toctree::
:maxdepth: 2

View file

@ -52,7 +52,8 @@ h1 {
}
.container.experimental,
#debugging-facilities {
#debugging-facilities,
#borg-recreate {
/* don't change text dimensions */
margin: 0 -30px; /* padding below + border width */
padding: 0 10px; /* 10 px visual margin between edge of text and the border */
@ -178,60 +179,3 @@ cite {
#common-options .option {
white-space: nowrap;
}
/* Remove the right-column max-width cap so content fills the full available width. */
#right-column {
max-width: none;
}
/* Hide the default RTD flyout since we show the version selector in the sidebar. */
readthedocs-flyout {
display: none !important;
}
/* Version selector in the sidebar. */
.version-selector {
padding: 0 22px;
margin: 7px 0 7px 0;
font-size: 14px;
}
.version-selector label {
display: block;
margin-bottom: 4px;
color: #000;
}
.version-selector select {
width: 100%;
padding: 4px;
background-color: #fafafa;
color: #000;
border: 1px solid #ccc;
border-radius: 3px;
}
.version-selector::after {
content: '';
display: block;
border-top: 1px solid #ccc;
margin: 7px 0 0 0;
}
/* Reduce top and bottom margin of searchbox block to 7px to match separator spacing. */
.sidebar-block:has(#main-search) {
margin-top: 7px;
margin-bottom: 7px;
}
/* Reduce the separator margin below the search block to 7px. */
.sphinxsidebar > .sidebar-block:has(#main-search):after {
margin: 7px 22px 0 22px;
}
/* Downloads line in the sidebar: a single line, left-aligned with the boxes
above it and the table of contents below it. */
.borg-downloads {
padding: 0 22px;
margin: 7px 0 7px 0;
font-size: 14px;
color: #000;
}
.borg-downloads:after {
content: '';
display: block;
border-top: 1px solid #ccc;
margin: 7px 0 0 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,807 +0,0 @@
.. _changelog_0x:
Change Log 0.x
==============
Version 0.30.0 (2016-01-23)
---------------------------
Compatibility notes:
- The new default logging level is WARNING. Previously, it was INFO, which was
more verbose. Use -v (or --info) to show once again log level INFO messages.
See the "general" section in the usage docs.
- For borg create, you need --list (in addition to -v) to see the long file
list (was needed so you can have e.g. --stats alone without the long list)
- See below about BORG_DELETE_I_KNOW_WHAT_I_AM_DOING (was:
BORG_CHECK_I_KNOW_WHAT_I_AM_DOING)
Bug fixes:
- fix crash when using borg create --dry-run --keep-tag-files, #570
- make sure teardown with cleanup happens for Cache and RepositoryCache,
avoiding leftover locks and TEMP dir contents, #285 (partially), #548
- fix locking KeyError, partial fix for #502
- log stats consistently, #526
- add abbreviated weekday to timestamp format, fixes #496
- strip whitespace when loading exclusions from file
- unset LD_LIBRARY_PATH before invoking ssh, fixes strange OpenSSL library
version warning when using the borg binary, #514
- add some error handling/fallback for C library loading, #494
- added BORG_DELETE_I_KNOW_WHAT_I_AM_DOING for check in "borg delete", #503
- remove unused "repair" rpc method name
New features:
- borg create: implement exclusions using regular expression patterns.
- borg create: implement inclusions using patterns.
- borg extract: support patterns, #361
- support different styles for patterns:
- fnmatch (`fm:` prefix, default when omitted), like borg <= 0.29.
- shell (`sh:` prefix) with `*` not matching directory separators and
`**/` matching 0..n directories
- path prefix (`pp:` prefix, for unifying borg create pp1 pp2 into the
patterns system), semantics like in borg <= 0.29
- regular expression (`re:`), new!
- --progress option for borg upgrade (#291) and borg delete <archive>
- update progress indication more often (e.g. for borg create within big
files or for borg check repo), #500
- finer chunker granularity for items metadata stream, #547, #487
- borg create --list is now used (in addition to -v) to enable the verbose
file list output
- display borg version below tracebacks, #532
Other changes:
- hashtable size (and thus: RAM and disk consumption) follows a growth policy:
grows fast while small, grows slower when getting bigger, #527
- Vagrantfile: use pyinstaller 3.1 to build binaries, freebsd sqlite3 fix,
fixes #569
- no separate binaries for centos6 any more because the generic linux binaries
also work on centos6 (or in general: on systems with a slightly older glibc
than debian7
- dev environment: require virtualenv<14.0 so we get a py32 compatible pip
- docs:
- add space-saving chunks.archive.d trick to FAQ
- important: clarify -v and log levels in usage -> general, please read!
- sphinx configuration: create a simple man page from usage docs
- add a repo server setup example
- disable unneeded SSH features in authorized_keys examples for security.
- borg prune only knows "--keep-within" and not "--within"
- add gource video to resources docs, #507
- add netbsd install instructions
- authors: make it more clear what refers to borg and what to attic
- document standalone binary requirements, #499
- rephrase the mailing list section
- development docs: run build_api and build_usage before tagging release
- internals docs: hash table max. load factor is 0.75 now
- markup, typo, grammar, phrasing, clarifications and other fixes.
- add gcc gcc-c++ to redhat/fedora/corora install docs, fixes #583
Version 0.29.0 (2015-12-13)
---------------------------
Compatibility notes:
- When upgrading to 0.29.0, you need to upgrade client as well as server
installations due to the locking and command-line interface changes; otherwise
you'll get an error message about an RPC protocol mismatch or a wrong command-line
option.
If you run a server that needs to support both old and new clients, it is
suggested that you have a "borg-0.28.2" and a "borg-0.29.0" command.
clients then can choose via e.g. "borg --remote-path=borg-0.29.0 ...".
- The default waiting time for a lock changed from infinity to 1 second for a
better interactive user experience. If the repo you want to access is
currently locked, borg will now terminate after 1s with an error message.
If you have scripts that should wait for the lock for a longer time, use
--lock-wait N (with N being the maximum wait time in seconds).
Bug fixes:
- hash table tuning (better chosen hashtable load factor 0.75 and prime initial
size of 1031 gave ~1000x speedup in some scenarios)
- avoid creation of an orphan lock for one case, #285
- --keep-tag-files: fix file mode and multiple tag files in one directory, #432
- fixes for "borg upgrade" (attic repo converter), #466
- remove --progress isatty magic (and also --no-progress option) again, #476
- borg init: display proper repo URL
- fix format of umask in help pages, #463
New features:
- implement --lock-wait, support timeout for UpgradableLock, #210
- implement borg break-lock command, #157
- include system info below traceback, #324
- sane remote logging, remote stderr, #461:
- remote log output: intercept it and log it via local logging system,
with "Remote: " prefixed to message. log remote tracebacks.
- remote stderr: output it to local stderr with "Remote: " prefixed.
- add --debug and --info (same as --verbose) to set the log level of the
builtin logging configuration (which otherwise defaults to warning), #426
note: there are few messages emitted at DEBUG level currently.
- optionally configure logging via env var BORG_LOGGING_CONF
- add --filter option for status characters: e.g. to show only the added
or modified files (and also errors), use "borg create -v --filter=AME ...".
- more progress indicators, #394
- use ISO-8601 date and time format, #375
- "borg check --prefix" to restrict archive checking to that name prefix, #206
Other changes:
- hashindex_add C implementation (speed up cache re-sync for new archives)
- increase FUSE read_size to 1024 (speed up metadata operations)
- check/delete/prune --save-space: free unused segments quickly, #239
- increase rpc protocol version to 2 (see also Compatibility notes), #458
- silence borg by default (via default log level WARNING)
- get rid of C compiler warnings, #391
- upgrade OS X FUSE to 3.0.9 on the OS X binary build system
- use python 3.5.1 to build binaries
- docs:
- new mailing list borgbackup@python.org, #468
- readthedocs: color and logo improvements
- load coverage icons over SSL (avoids mixed content)
- more precise binary installation steps
- update release procedure docs about OS X FUSE
- FAQ entry about unexpected 'A' status for unchanged file(s), #403
- add docs about 'E' file status
- add "borg upgrade" docs, #464
- add developer docs about output and logging
- clarify encryption, add note about client-side encryption
- add resources section, with videos, talks, presentations, #149
- Borg moved to Arch Linux [community]
- fix wrong installation instructions for archlinux
Version 0.28.2 (2015-11-15)
---------------------------
New features:
- borg create --exclude-if-present TAGFILE - exclude directories that have the
given file from the backup. You can additionally give --keep-tag-files to
preserve just the directory roots and the tag-files (but not back up other
directory contents), #395, attic #128, attic #142
Other changes:
- do not create docs sources at build time (just have them in the repo),
completely remove have_cython() hack, do not use the "mock" library at build
time, #384
- avoid hidden import, make it easier for PyInstaller, easier fix for #218
- docs:
- add description of item flags / status output, fixes #402
- explain how to regenerate usage and API files (build_api or
build_usage) and when to commit usage files directly into git, #384
- minor install docs improvements
Version 0.28.1 (2015-11-08)
---------------------------
Bug fixes:
- do not try to build api / usage docs for production install,
fixes unexpected "mock" build dependency, #384
Other changes:
- avoid using msgpack.packb at import time
- fix formatting issue in changes.rst
- fix build on readthedocs
Version 0.28.0 (2015-11-08)
---------------------------
Compatibility notes:
- changed return codes (exit codes), see docs. in short:
old: 0 = ok, 1 = error. now: 0 = ok, 1 = warning, 2 = error
New features:
- refactor return codes (exit codes), fixes #61
- add --show-rc option enable "terminating with X status, rc N" output, fixes 58, #351
- borg create backups atime and ctime additionally to mtime, fixes #317
- extract: support atime additionally to mtime
- FUSE: support ctime and atime additionally to mtime
- support borg --version
- emit a warning if we have a slow msgpack installed
- borg list --prefix=thishostname- REPO, fixes #205
- Debug commands (do not use except if you know what you do: debug-get-obj,
debug-put-obj, debug-delete-obj, debug-dump-archive-items.
Bug fixes:
- setup.py: fix bug related to BORG_LZ4_PREFIX processing
- fix "check" for repos that have incomplete chunks, fixes #364
- borg mount: fix unlocking of repository at umount time, fixes #331
- fix reading files without touching their atime, #334
- non-ascii ACL fixes for Linux, FreeBSD and OS X, #277
- fix acl_use_local_uid_gid() and add a test for it, attic #359
- borg upgrade: do not upgrade repositories in place by default, #299
- fix cascading failure with the index conversion code, #269
- borg check: implement 'cmdline' archive metadata value decoding, #311
- fix RobustUnpacker, it missed some metadata keys (new atime and ctime keys
were missing, but also bsdflags). add check for unknown metadata keys.
- create from stdin: also save atime, ctime (cosmetic)
- use default_notty=False for confirmations, fixes #345
- vagrant: fix msgpack installation on centos, fixes #342
- deal with unicode errors for symlinks in same way as for regular files and
have a helpful warning message about how to fix wrong locale setup, fixes #382
- add ACL keys the RobustUnpacker must know about
Other changes:
- improve file size displays, more flexible size formatters
- explicitly commit to the units standard, #289
- archiver: add E status (means that an error occurred when processing this
(single) item
- do binary releases via "github releases", closes #214
- create: use -x and --one-file-system (was: --do-not-cross-mountpoints), #296
- a lot of changes related to using "logging" module and screen output, #233
- show progress display if on a tty, output more progress information, #303
- factor out status output so it is consistent, fix surrogates removal,
maybe fixes #309
- move away from RawConfigParser to ConfigParser
- archive checker: better error logging, give chunk_id and sequence numbers
(can be used together with borg debug-dump-archive-items).
- do not mention the deprecated passphrase mode
- emit a deprecation warning for --compression N (giving a just a number)
- misc .coverragerc fixes (and coverage measurement improvements), fixes #319
- refactor confirmation code, reduce code duplication, add tests
- prettier error messages, fixes #307, #57
- tests:
- add a test to find disk-full issues, #327
- travis: also run tests on Python 3.5
- travis: use tox -r so it rebuilds the tox environments
- test the generated pyinstaller-based binary by archiver unit tests, #215
- vagrant: tests: announce whether fakeroot is used or not
- vagrant: add vagrant user to fuse group for debianoid systems also
- vagrant: llfuse install on darwin needs pkgconfig installed
- vagrant: use pyinstaller from develop branch, fixes #336
- benchmarks: test create, extract, list, delete, info, check, help, fixes #146
- benchmarks: test with both the binary and the python code
- archiver tests: test with both the binary and the python code, fixes #215
- make basic test more robust
- docs:
- moved docs to borgbackup.readthedocs.org, #155
- a lot of fixes and improvements, use mobile-friendly RTD standard theme
- use zlib,6 compression in some examples, fixes #275
- add missing rename usage to docs, closes #279
- include the help offered by borg help <topic> in the usage docs, fixes #293
- include a list of major changes compared to attic into README, fixes #224
- add OS X install instructions, #197
- more details about the release process, #260
- fix linux glibc requirement (binaries built on debian7 now)
- build: move usage and API generation to setup.py
- update docs about return codes, #61
- remove api docs (too much breakage on rtd)
- borgbackup install + basics presentation (asciinema)
- describe the current style guide in documentation
- add section about debug commands
- warn about not running out of space
- add example for rename
- improve chunker params docs, fixes #362
- minor development docs update
Version 0.27.0 (2015-10-07)
---------------------------
New features:
- "borg upgrade" command - attic -> borg one time converter / migration, #21
- temporary hack to avoid using lots of disk space for chunks.archive.d, #235:
To use it: rm -rf chunks.archive.d ; touch chunks.archive.d
- respect XDG_CACHE_HOME, attic #181
- add support for arbitrary SSH commands, attic #99
- borg delete --cache-only REPO (only delete cache, not REPO), attic #123
Bug fixes:
- use Debian 7 (wheezy) to build pyinstaller borgbackup binaries, fixes slow
down observed when running the Centos6-built binary on Ubuntu, #222
- do not crash on empty lock.roster, fixes #232
- fix multiple issues with the cache config version check, #234
- fix segment entry header size check, attic #352
plus other error handling improvements / code deduplication there.
- always give segment and offset in repo IntegrityErrors
Other changes:
- stop producing binary wheels, remove docs about it, #147
- docs:
- add warning about prune
- generate usage include files only as needed
- development docs: add Vagrant section
- update / improve / reformat FAQ
- hint to single-file pyinstaller binaries from README
Version 0.26.1 (2015-09-28)
---------------------------
This is a minor update, just docs and new pyinstaller binaries.
- docs update about python and binary requirements
- better docs for --read-special, fix #220
- re-built the binaries, fix #218 and #213 (glibc version issue)
- update web site about single-file pyinstaller binaries
Note: if you did a python-based installation, there is no need to upgrade.
Version 0.26.0 (2015-09-19)
---------------------------
New features:
- Faster cache sync (do all in one pass, remove tar/compression stuff), #163
- BORG_REPO env var to specify the default repo, #168
- read special files as if they were regular files, #79
- implement borg create --dry-run, attic issue #267
- Normalize paths before pattern matching on OS X, #143
- support OpenBSD and NetBSD (except xattrs/ACLs)
- support / run tests on Python 3.5
Bug fixes:
- borg mount repo: use absolute path, attic #200, attic #137
- chunker: use off_t to get 64bit on 32bit platform, #178
- initialize chunker fd to -1, so it's not equal to STDIN_FILENO (0)
- fix reaction to "no" answer at delete repo prompt, #182
- setup.py: detect lz4.h header file location
- to support python < 3.2.4, add less buggy argparse lib from 3.2.6 (#194)
- fix for obtaining ``char *`` from temporary Python value (old code causes
a compile error on Mint 17.2)
- llfuse 0.41 install troubles on some platforms, require < 0.41
(UnicodeDecodeError exception due to non-ascii llfuse setup.py)
- cython code: add some int types to get rid of unspecific python add /
subtract operations (avoid ``undefined symbol FPE_``... error on some platforms)
- fix verbose mode display of stdin backup
- extract: warn if a include pattern never matched, fixes #209,
implement counters for Include/ExcludePatterns
- archive names with slashes are invalid, attic issue #180
- chunker: add a check whether the POSIX_FADV_DONTNEED constant is defined -
fixes building on OpenBSD.
Other changes:
- detect inconsistency / corruption / hash collision, #170
- replace versioneer with setuptools_scm, #106
- docs:
- pkg-config is needed for llfuse installation
- be more clear about pruning, attic issue #132
- unit tests:
- xattr: ignore security.selinux attribute showing up
- ext3 seems to need a bit more space for a sparse file
- do not test lzma level 9 compression (avoid MemoryError)
- work around strange mtime granularity issue on netbsd, fixes #204
- ignore st_rdev if file is not a block/char device, fixes #203
- stay away from the setgid and sticky mode bits
- use Vagrant to do easy cross-platform testing (#196), currently:
- Debian 7 "wheezy" 32bit, Debian 8 "jessie" 64bit
- Ubuntu 12.04 32bit, Ubuntu 14.04 64bit
- Centos 7 64bit
- FreeBSD 10.2 64bit
- OpenBSD 5.7 64bit
- NetBSD 6.1.5 64bit
- Darwin (OS X Yosemite)
Version 0.25.0 (2015-08-29)
---------------------------
Compatibility notes:
- lz4 compression library (liblz4) is a new requirement (#156)
- the new compression code is very compatible: as long as you stay with zlib
compression, older borg releases will still be able to read data from a
repo/archive made with the new code (note: this is not the case for the
default "none" compression, use "zlib,0" if you want a "no compression" mode
that can be read by older borg). Also the new code is able to read repos and
archives made with older borg versions (for all zlib levels 0..9).
Deprecations:
- --compression N (with N being a number, as in 0.24) is deprecated.
We keep the --compression 0..9 for now not to break scripts, but it is
deprecated and will be removed later, so better fix your scripts now:
--compression 0 (as in 0.24) is the same as --compression zlib,0 (now).
BUT: if you do not want compression, use --compression none
(which is the default).
--compression 1 (in 0.24) is the same as --compression zlib,1 (now)
--compression 9 (in 0.24) is the same as --compression zlib,9 (now)
New features:
- create --compression none (default, means: do not compress, just pass through
data "as is". this is more efficient than zlib level 0 as used in borg 0.24)
- create --compression lz4 (super-fast, but not very high compression)
- create --compression zlib,N (slower, higher compression, default for N is 6)
- create --compression lzma,N (slowest, highest compression, default N is 6)
- honor the nodump flag (UF_NODUMP) and do not back up such items
- list --short just outputs a simple list of the files/directories in an archive
Bug fixes:
- fixed --chunker-params parameter order confusion / malfunction, fixes #154
- close fds of segments we delete (during compaction)
- close files which fell out the lrucache
- fadvise DONTNEED now is only called for the byte range actually read, not for
the whole file, fixes #158.
- fix issue with negative "all archives" size, fixes #165
- restore_xattrs: ignore if setxattr fails with EACCES, fixes #162
Other changes:
- remove fakeroot requirement for tests, tests run faster without fakeroot
(test setup does not fail any more without fakeroot, so you can run with or
without fakeroot), fixes #151 and #91.
- more tests for archiver
- recover_segment(): don't assume we have an fd for segment
- lrucache refactoring / cleanup, add dispose function, py.test tests
- generalize hashindex code for any key length (less hardcoding)
- lock roster: catch file not found in remove() method and ignore it
- travis CI: use requirements file
- improved docs:
- replace hack for llfuse with proper solution (install libfuse-dev)
- update docs about compression
- update development docs about fakeroot
- internals: add some words about lock files / locking system
- support: mention BountySource and for what it can be used
- theme: use a lighter green
- add pypi, wheel, dist package based install docs
- split install docs into system-specific preparations and generic instructions
Version 0.24.0 (2015-08-09)
---------------------------
Incompatible changes (compared to 0.23):
- borg now always issues --umask NNN option when invoking another borg via ssh
on the repository server. By that, it's making sure it uses the same umask
for remote repos as for local ones. Because of this, you must upgrade both
server and client(s) to 0.24.
- the default umask is 077 now (if you do not specify via --umask) which might
be a different one as you used previously. The default umask avoids that
you accidentally give access permissions for group and/or others to files
created by borg (e.g. the repository).
Deprecations:
- "--encryption passphrase" mode is deprecated, see #85 and #97.
See the new "--encryption repokey" mode for a replacement.
New features:
- borg create --chunker-params ... to configure the chunker, fixes #16
(attic #302, attic #300, and somehow also #41).
This can be used to reduce memory usage caused by chunk management overhead,
so borg does not create a huge chunks index/repo index and eats all your RAM
if you back up lots of data in huge files (like VM disk images).
See docs/misc/create_chunker-params.txt for more information.
- borg info now reports chunk counts in the chunk index.
- borg create --compression 0..9 to select zlib compression level, fixes #66
(attic #295).
- borg init --encryption repokey (to store the encryption key into the repo),
fixes #85
- improve at-end error logging, always log exceptions and set exit_code=1
- LoggedIO: better error checks / exceptions / exception handling
- implement --remote-path to allow non-default-path borg locations, #125
- implement --umask M and use 077 as default umask for better security, #117
- borg check: give a named single archive to it, fixes #139
- cache sync: show progress indication
- cache sync: reimplement the chunk index merging in C
Bug fixes:
- fix segfault that happened for unreadable files (chunker: n needs to be a
signed size_t), #116
- fix the repair mode, #144
- repo delete: add destroy to allowed rpc methods, fixes issue #114
- more compatible repository locking code (based on mkdir), maybe fixes #92
(attic #317, attic #201).
- better Exception msg if no Borg is installed on the remote repo server, #56
- create a RepositoryCache implementation that can cope with >2GiB,
fixes attic #326.
- fix Traceback when running check --repair, attic #232
- clarify help text, fixes #73.
- add help string for --no-files-cache, fixes #140
Other changes:
- improved docs:
- added docs/misc directory for misc. writeups that won't be included
"as is" into the html docs.
- document environment variables and return codes (attic #324, attic #52)
- web site: add related projects, fix web site url, IRC #borgbackup
- Fedora/Fedora-based install instructions added to docs
- Cygwin-based install instructions added to docs
- updated AUTHORS
- add FAQ entries about redundancy / integrity
- clarify that borg extract uses the cwd as extraction target
- update internals doc about chunker params, memory usage and compression
- added docs about development
- add some words about resource usage in general
- document how to back up a raw disk
- add note about how to run borg from virtual env
- add solutions for (ll)fuse installation problems
- document what borg check does, fixes #138
- reorganize borgbackup.github.io sidebar, prev/next at top
- deduplicate and refactor the docs / README.rst
- use borg-tmp as prefix for temporary files / directories
- short prune options without "keep-" are deprecated, do not suggest them
- improved tox configuration
- remove usage of unittest.mock, always use mock from pypi
- use entrypoints instead of scripts, for better use of the wheel format and
modern installs
- add requirements.d/development.txt and modify tox.ini
- use travis-ci for testing based on Linux and (new) OS X
- use coverage.py, pytest-cov and codecov.io for test coverage support
I forgot to list some stuff already implemented in 0.23.0, here they are:
New features:
- efficient archive list from manifest, meaning a big speedup for slow
repo connections and "list <repo>", "delete <repo>", "prune" (attic #242,
attic #167)
- big speedup for chunks cache sync (esp. for slow repo connections), fixes #18
- hashindex: improve error messages
Other changes:
- explicitly specify binary mode to open binary files
- some easy micro optimizations
Version 0.23.0 (2015-06-11)
---------------------------
Incompatible changes (compared to attic, fork related):
- changed sw name and cli command to "borg", updated docs
- package name (and name in urls) uses "borgbackup" to have fewer collisions
- changed repo / cache internal magic strings from ATTIC* to BORG*,
changed cache location to .cache/borg/ - this means that it currently won't
accept attic repos (see issue #21 about improving that)
Bug fixes:
- avoid defect python-msgpack releases, fixes attic #171, fixes attic #185
- fix traceback when trying to do unsupported passphrase change, fixes attic #189
- datetime does not like the year 10.000, fixes attic #139
- fix "info" all archives stats, fixes attic #183
- fix parsing with missing microseconds, fixes attic #282
- fix misleading hint the fuse ImportError handler gave, fixes attic #237
- check unpacked data from RPC for tuple type and correct length, fixes attic #127
- fix Repository._active_txn state when lock upgrade fails
- give specific path to xattr.is_enabled(), disable symlink setattr call that
always fails
- fix test setup for 32bit platforms, partial fix for attic #196
- upgraded versioneer, PEP440 compliance, fixes attic #257
New features:
- less memory usage: add global option --no-cache-files
- check --last N (only check the last N archives)
- check: sort archives in reverse time order
- rename repo::oldname newname (rename repository)
- create -v output more informative
- create --progress (backup progress indicator)
- create --timestamp (utc string or reference file/dir)
- create: if "-" is given as path, read binary from stdin
- extract: if --stdout is given, write all extracted binary data to stdout
- extract --sparse (simple sparse file support)
- extra debug information for 'fread failed'
- delete <repo> (deletes whole repo + local cache)
- FUSE: reflect deduplication in allocated blocks
- only allow whitelisted RPC calls in server mode
- normalize source/exclude paths before matching
- use posix_fadvise not to spoil the OS cache, fixes attic #252
- toplevel error handler: show tracebacks for better error analysis
- sigusr1 / sigint handler to print current file infos - attic PR #286
- RPCError: include the exception args we get from remote
Other changes:
- source: misc. cleanups, pep8, style
- docs and faq improvements, fixes, updates
- cleanup crypto.pyx, make it easier to adapt to other AES modes
- do os.fsync like recommended in the python docs
- source: Let chunker optionally work with os-level file descriptor.
- source: Linux: remove duplicate os.fsencode calls
- source: refactor _open_rb code a bit, so it is more consistent / regular
- source: refactor indicator (status) and item processing
- source: use py.test for better testing, flake8 for code style checks
- source: fix tox >=2.0 compatibility (test runner)
- pypi package: add python version classifiers, add FreeBSD to platforms
Attic Changelog
---------------
Here you can see the full list of changes between each Attic release until Borg
forked from Attic:
Version 0.17
~~~~~~~~~~~~
(bugfix release, released on X)
- Fix hashindex ARM memory alignment issue (#309)
- Improve hashindex error messages (#298)
Version 0.16
~~~~~~~~~~~~
(bugfix release, released on May 16, 2015)
- Fix typo preventing the security confirmation prompt from working (#303)
- Improve handling of systems with improperly configured file system encoding (#289)
- Fix "All archives" output for attic info. (#183)
- More user friendly error message when repository key file is not found (#236)
- Fix parsing of iso 8601 timestamps with zero microseconds (#282)
Version 0.15
~~~~~~~~~~~~
(bugfix release, released on Apr 15, 2015)
- xattr: Be less strict about unknown/unsupported platforms (#239)
- Reduce repository listing memory usage (#163).
- Fix BrokenPipeError for remote repositories (#233)
- Fix incorrect behavior with two character directory names (#265, #268)
- Require approval before accessing relocated/moved repository (#271)
- Require approval before accessing previously unknown unencrypted repositories (#271)
- Fix issue with hash index files larger than 2GB.
- Fix Python 3.2 compatibility issue with noatime open() (#164)
- Include missing pyx files in dist files (#168)
Version 0.14
~~~~~~~~~~~~
(feature release, released on Dec 17, 2014)
- Added support for stripping leading path segments (#95)
"attic extract --strip-segments X"
- Add workaround for old Linux systems without acl_extended_file_no_follow (#96)
- Add MacPorts' path to the default openssl search path (#101)
- HashIndex improvements, eliminates unnecessary IO on low memory systems.
- Fix "Number of files" output for attic info. (#124)
- limit create file permissions so files aren't read while restoring
- Fix issue with empty xattr values (#106)
Version 0.13
~~~~~~~~~~~~
(feature release, released on Jun 29, 2014)
- Fix sporadic "Resource temporarily unavailable" when using remote repositories
- Reduce file cache memory usage (#90)
- Faster AES encryption (utilizing AES-NI when available)
- Experimental Linux, OS X and FreeBSD ACL support (#66)
- Added support for backup and restore of BSDFlags (OSX, FreeBSD) (#56)
- Fix bug where xattrs on symlinks were not correctly restored
- Added cachedir support. CACHEDIR.TAG compatible cache directories
can now be excluded using ``--exclude-caches`` (#74)
- Fix crash on extreme mtime timestamps (year 2400+) (#81)
- Fix Python 3.2 specific lockf issue (EDEADLK)
Version 0.12
~~~~~~~~~~~~
(feature release, released on April 7, 2014)
- Python 3.4 support (#62)
- Various documentation improvements a new style
- ``attic mount`` now supports mounting an entire repository not only
individual archives (#59)
- Added option to restrict remote repository access to specific path(s):
``attic serve --restrict-to-path X`` (#51)
- Include "all archives" size information in "--stats" output. (#54)
- Added ``--stats`` option to ``attic delete`` and ``attic prune``
- Fixed bug where ``attic prune`` used UTC instead of the local time zone
when determining which archives to keep.
- Switch to SI units (Power of 1000 instead 1024) when printing file sizes
Version 0.11
~~~~~~~~~~~~
(feature release, released on March 7, 2014)
- New "check" command for repository consistency checking (#24)
- Documentation improvements
- Fix exception during "attic create" with repeated files (#39)
- New "--exclude-from" option for attic create/extract/verify.
- Improved archive metadata deduplication.
- "attic verify" has been deprecated. Use "attic extract --dry-run" instead.
- "attic prune --hourly|daily|..." has been deprecated.
Use "attic prune --keep-hourly|daily|..." instead.
- Ignore xattr errors during "extract" if not supported by the filesystem. (#46)
Version 0.10
~~~~~~~~~~~~
(bugfix release, released on Jan 30, 2014)
- Fix deadlock when extracting 0 sized files from remote repositories
- "--exclude" wildcard patterns are now properly applied to the full path
not just the file name part (#5).
- Make source code endianness agnostic (#1)
Version 0.9
~~~~~~~~~~~
(feature release, released on Jan 23, 2014)
- Remote repository speed and reliability improvements.
- Fix sorting of segment names to ignore NFS left over files. (#17)
- Fix incorrect display of time (#13)
- Improved error handling / reporting. (#12)
- Use fcntl() instead of flock() when locking repository/cache. (#15)
- Let ssh figure out port/user if not specified so we don't override .ssh/config (#9)
- Improved libcrypto path detection (#23).
Version 0.8.1
~~~~~~~~~~~~~
(bugfix release, released on Oct 4, 2013)
- Fix segmentation fault issue.
Version 0.8
~~~~~~~~~~~
(feature release, released on Oct 3, 2013)
- Fix xattr issue when backing up sshfs filesystems (#4)
- Fix issue with excessive index file size (#6)
- Support access of read only repositories.
- New syntax to enable repository encryption:
attic init --encryption="none|passphrase|keyfile".
- Detect and abort if repository is older than the cache.
Version 0.7
~~~~~~~~~~~
(feature release, released on Aug 5, 2013)
- Ported to FreeBSD
- Improved documentation
- Experimental: Archives mountable as FUSE filesystems.
- The "user." prefix is no longer stripped from xattrs on Linux
Version 0.6.1
~~~~~~~~~~~~~
(bugfix release, released on July 19, 2013)
- Fixed an issue where mtime was not always correctly restored.
Version 0.6
~~~~~~~~~~~
First public release on July 9, 2013

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
# Documentation build configuration file, created by
# documentation build configuration file, created by
# sphinx-quickstart on Sat Sep 10 18:18:25 2011.
#
# This file is execfile()d with the current directory set to its containing directory.
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
@ -12,164 +12,167 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
import sys
import os
sys.path.insert(0, os.path.abspath("../src"))
import sys, os
sys.path.insert(0, os.path.abspath('../src'))
from borg import __version__ as sw_version
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = ".rst"
source_suffix = '.rst'
# The encoding of source files.
# source_encoding = 'utf-8-sig'
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = "index"
master_doc = 'index'
# General information about the project.
project = "Borg - Deduplicating Archiver"
copyright = "2010-2014 Jonas Borgström, 2015-2026 The Borg Collective (see AUTHORS file)"
project = 'Borg - Deduplicating Archiver'
copyright = '2010-2014 Jonas Borgström, 2015-2023 The Borg Collective (see AUTHORS file)'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
split_char = "+" if "+" in sw_version else "-"
split_char = '+' if '+' in sw_version else '-'
version = sw_version.split(split_char)[0]
# The full version, including alpha/beta/rc tags.
release = version
suppress_warnings = ["image.nonlocal_uri"]
suppress_warnings = ['image.nonlocal_uri']
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = "%Y-%m-%d"
today_fmt = '%Y-%m-%d'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
#default_role = None
# The Borg docs contain no or very little Python docs.
# Thus, the primary domain is RST.
primary_domain = "rst"
# Thus, the primary domain is rst.
primary_domain = 'rst'
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of built-in themes.
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
import guzzle_sphinx_theme
html_theme_path = guzzle_sphinx_theme.html_theme_path()
html_theme = "guzzle_sphinx_theme"
html_theme = 'guzzle_sphinx_theme'
def set_rst_settings(app):
app.env.settings.update({"field_name_limit": 0, "option_limit": 0})
app.env.settings.update({
'field_name_limit': 0,
'option_limit': 0,
})
def setup(app):
app.setup_extension("sphinxcontrib.jquery")
app.add_css_file("css/borg.css")
app.connect("builder-inited", set_rst_settings)
app.add_css_file('css/borg.css')
app.connect('builder-inited', set_rst_settings)
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {"project_nav_name": "Borg %s" % version}
html_theme_options = {
'project_nav_name': 'Borg %s' % version,
}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = ['_themes']
#html_theme_path = ['_themes']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = "_static/logo.svg"
html_logo = '_static/logo.svg'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = "_static/favicon.ico"
html_favicon = '_static/favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["borg_theme"]
html_static_path = ['borg_theme']
html_extra_path = ["../src/borg/paperkey.html"]
html_extra_path = ['../src/borg/paperkey.html']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = "%Y-%m-%d"
html_last_updated_fmt = '%Y-%m-%d'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
html_use_smartypants = True
smartquotes_action = "qe" # no D in there means "do not transform -- and ---"
smartquotes_action = 'qe' # no D in there means "do not transform -- and ---"
# Custom sidebar templates, maps document names to template names.
html_sidebars = {"**": ["logo-text.html", "versionselector.html", "searchbox.html", "downloads.html", "globaltoc.html"]}
html_sidebars = {
'**': ['logo-text.html', 'searchbox.html', 'globaltoc.html'],
}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
#html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
#html_domain_indices = True
# If false, no index is generated.
html_use_index = False
# If true, the index is split into individual pages for each letter.
# html_split_index = False
#html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
@ -183,45 +186,57 @@ html_show_copyright = False
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = "borgdoc"
htmlhelp_basename = 'borgdoc'
# -- Options for LaTeX output --------------------------------------------------
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [("book", "Borg.tex", "Borg Documentation", "The Borg Collective", "manual")]
latex_documents = [
('book', 'Borg.tex', 'Borg Documentation',
'The Borg Collective', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
latex_logo = "_static/logo.pdf"
latex_logo = '_static/logo.pdf'
latex_elements = {"papersize": "a4paper", "pointsize": "10pt", "figure_align": "H"}
latex_elements = {
'papersize': 'a4paper',
'pointsize': '10pt',
'figure_align': 'H',
}
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
#latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
latex_show_urls = "footnote"
latex_show_urls = 'footnote'
# Additional stuff for the LaTeX preamble.
# latex_preamble = ''
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
latex_appendices = ["support", "changes", "authors"]
latex_appendices = [
'support',
'resources',
'changes',
'authors',
]
# If false, no module index is generated.
# latex_domain_indices = True
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
@ -229,23 +244,21 @@ latex_appendices = ["support", "changes", "authors"]
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(
"usage",
"borg",
"BorgBackup is a deduplicating backup program with optional compression and authenticated encryption.",
["The Borg Collective (see AUTHORS file)"],
1,
)
('usage', 'borg',
'BorgBackup is a deduplicating backup program with optional compression and authenticated encryption.',
['The Borg Collective (see AUTHORS file)'],
1),
]
extensions = [
"sphinx.ext.extlinks",
"sphinx.ext.autodoc",
"sphinx.ext.todo",
"sphinx.ext.coverage",
"sphinx.ext.viewcode",
"sphinxcontrib.jquery", # jquery is not included anymore by default
"guzzle_sphinx_theme", # register the theme as an extension to generate a sitemap.xml
'sphinx.ext.extlinks',
'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
]
extlinks = {"issue": ("https://github.com/borgbackup/borg/issues/%s", "#%s")}
extlinks = {
'issue': ('https://github.com/borgbackup/borg/issues/%s', '#%s'),
'targz_url': ('https://pypi.python.org/packages/source/b/borgbackup/%%s-%s.tar.gz' % version, None),
}

View file

@ -14,4 +14,3 @@ This chapter details deployment strategies for the following scenarios.
deployment/automated-local
deployment/image-backup
deployment/pull-backup
deployment/non-root-user

View file

@ -14,13 +14,13 @@ systemd and udev.
Overview
--------
A udev rule is created to trigger on the addition of block devices. The rule contains a tag
that triggers systemd to start a one-shot service. The one-shot service executes a script in
An udev rule is created to trigger on the addition of block devices. The rule contains a tag
that triggers systemd to start a oneshot service. The oneshot service executes a script in
the standard systemd service environment, which automatically captures stdout/stderr and
logs it to the journal.
The script mounts the added block device if it is a registered backup drive and creates
backups on it. When done, it optionally unmounts the filesystem and spins the drive down,
The script mounts the added block device, if it is a registered backup drive, and creates
backups on it. When done, it optionally unmounts the file system and spins the drive down,
so that it may be physically disconnected.
Configuring the system
@ -29,13 +29,12 @@ Configuring the system
First, create the ``/etc/backups`` directory (as root).
All configuration goes into this directory.
Find out the ID of the partition table of your backup disk (here assumed to be /dev/sdz)::
Find out the ID of the partition table of your backup disk (here assumed to be /dev/sdz):
lsblk --fs -o +PTUUID /dev/sdz
Then, create ``/etc/backups/80-backup.rules`` with the following content (all on one line)::
Then, create ``/etc/backups/40-backup.rules`` with the following content (all on one line)::
ACTION=="add", SUBSYSTEM=="block", ENV{ID_PART_TABLE_UUID}=="<the PTUUID you just noted>", TAG+="systemd", ENV{SYSTEMD_WANTS}+="automatic-backup.service"
ACTION=="add", SUBSYSTEM=="block", ENV{ID_PART_TABLE_UUID}=="<the PTUUID you just noted>", TAG+="systemd", ENV{SYSTEMD_WANTS}="automatic-backup.service"
The "systemd" tag in conjunction with the SYSTEMD_WANTS environment variable has systemd
launch the "automatic-backup" service, which we will create next, as the
@ -47,8 +46,8 @@ launch the "automatic-backup" service, which we will create next, as the
Type=oneshot
ExecStart=/etc/backups/run.sh
Now, create the main backup script, ``/etc/backups/run.sh``. Below is a template;
modify it to suit your needs (e.g., more backup sets, dumping databases, etc.).
Now, create the main backup script, ``/etc/backups/run.sh``. Below is a template,
modify it to suit your needs (e.g. more backup sets, dumping databases etc.).
.. code-block:: bash
@ -94,8 +93,8 @@ modify it to suit your needs (e.g., more backup sets, dumping databases, etc.).
echo "Disk $uuid is a backup disk"
partition_path=/dev/disk/by-uuid/$uuid
# Mount filesystem if not already done. This assumes that if something is already
# mounted at $MOUNTPOINT, it is the backup drive. It will not find the drive if
# Mount file system if not already done. This assumes that if something is already
# mounted at $MOUNTPOINT, it is the backup drive. It won't find the drive if
# it was mounted somewhere else.
findmnt $MOUNTPOINT >/dev/null || mount $partition_path $MOUNTPOINT
drive=$(lsblk --inverse --noheadings --list --paths --output name $partition_path | head --lines 1)
@ -106,13 +105,13 @@ modify it to suit your needs (e.g., more backup sets, dumping databases, etc.).
#
# Options for borg create
BORG_OPTS="--stats --one-file-system --compression lz4"
BORG_OPTS="--stats --one-file-system --compression lz4 --checkpoint-interval 86400"
# Set BORG_PASSPHRASE or BORG_PASSCOMMAND somewhere around here, using export,
# if encryption is used.
# Because no one can answer these questions non-interactively, it is better to
# fail quickly instead of hanging.
# No one can answer if Borg asks these questions, it is better to just fail quickly
# instead of hanging.
export BORG_RELOCATED_REPO_ACCESS_IS_OK=no
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no
@ -128,8 +127,8 @@ modify it to suit your needs (e.g., more backup sets, dumping databases, etc.).
$TARGET::$DATE-$$-system \
/ /boot
# /home is often a separate partition/filesystem.
# Even if it is not (add --exclude /home above), it probably makes sense
# /home is often a separate partition / file system.
# Even if it isn't (add --exclude /home above), it probably makes sense
# to have /home in a separate archive.
borg create $BORG_OPTS \
--exclude 'sh:home/*/.cache' \
@ -151,20 +150,21 @@ modify it to suit your needs (e.g., more backup sets, dumping databases, etc.).
fi
Create the ``/etc/backups/autoeject`` file to have the script automatically eject the drive
after creating the backup. Rename the file to something else (e.g., ``/etc/backups/autoeject-no``)
when you want to do something with the drive after creating backups (e.g., running checks).
after creating the backup. Rename the file to something else (e.g. ``/etc/backup/autoeject-no``)
when you want to do something with the drive after creating backups (e.g running check).
Create the ``/etc/backups/backup-suspend`` file if the machine should suspend after completing
the backup. Don't forget to disconnect the device physically before resuming,
the backup. Don't forget to physically disconnect the device before resuming,
otherwise you'll enter a cycle. You can also add an option to power down instead.
Create an empty ``/etc/backups/backup.disks`` file, in which you will register your backup drives.
Create an empty ``/etc/backups/backup.disks`` file, you'll register your backup drives
there.
Finally, enable the udev rules and services:
The last part is to actually enable the udev rules and services:
.. code-block:: bash
ln -s /etc/backups/80-backup.rules /etc/udev/rules.d/80-backup.rules
ln -s /etc/backups/40-backup.rules /etc/udev/rules.d/40-backup.rules
ln -s /etc/backups/automatic-backup.service /etc/systemd/system/automatic-backup.service
systemctl daemon-reload
udevadm control --reload
@ -173,13 +173,13 @@ Adding backup hard drives
-------------------------
Connect your backup hard drive. Format it, if not done already.
Find the UUID of the filesystem on which backups should be stored::
Find the UUID of the file system that backups should be stored on::
lsblk -o+uuid,label
Record the UUID in the ``/etc/backups/backup.disks`` file.
Note the UUID into the ``/etc/backup/backup.disks`` file.
Mount the drive at /mnt/backup.
Mount the drive to /mnt/backup.
Initialize a Borg repository at the location indicated by ``TARGET``::
@ -197,14 +197,14 @@ See backup logs using journalctl::
Security considerations
-----------------------
The script as shown above will mount any filesystem with a UUID listed in
``/etc/backups/backup.disks``. The UUID check is a safety/annoyance-reduction
The script as shown above will mount any file system with an UUID listed in
``/etc/backup/backup.disks``. The UUID check is a safety / annoyance-reduction
mechanism to keep the script from blowing up whenever a random USB thumb drive is connected.
It is not meant as a security mechanism. Mounting filesystems and reading repository
data exposes additional attack surfaces (kernel filesystem drivers,
possibly userspace services, and Borg itself). On the other hand, someone
It is not meant as a security mechanism. Mounting file systems and reading repository
data exposes additional attack surfaces (kernel file system drivers,
possibly user space services and Borg itself). On the other hand, someone
standing right next to your computer can attempt a lot of attacks, most of which
are easier to do than, e.g., exploiting filesystems (installing a physical keylogger,
are easier to do than e.g. exploiting file systems (installing a physical key logger,
DMA attacks, stealing the machine, ...).
Borg ensures that backups are not created on random drives that "just happen"

View file

@ -1,56 +1,47 @@
.. include:: ../global.rst.inc
.. highlight:: none
.. _central-backup-server:
Central repository server with Ansible or Salt
==============================================
This section gives an example of how to set up a Borg repository server for multiple
This section will give an example how to setup a borg repository server for multiple
clients.
.. note::
This example predates Borg 2 and uses the legacy ``ssh://`` transport (served
by ``borg serve``) and ``borg init``. With Borg 2, the ``ssh://`` transport is
only used for legacy borg 1.x (v1) repositories; for current repositories use a
``rest://`` repository instead (Borg connects via ssh and runs a borgstore REST
server on the remote host), and use ``borg repo-create`` instead of ``borg init``.
Machines
--------
This section uses multiple machines, referred to by their
respective fully qualified domain names (FQDNs).
There are multiple machines used in this section and will further be named by their
respective fully qualified domain name (fqdn).
* The backup server: `backup01.srv.local`
* The clients:
- John Doe's desktop: `johndoe.clnt.local`
- Web server 01: `web01.srv.local`
- Webserver 01: `web01.srv.local`
- Application server 01: `app01.srv.local`
User and group
--------------
The repository server should have a single UNIX user for all the clients.
The repository server needs to have only one UNIX user for all the clients.
Recommended user and group with additional settings:
* User: `backup`
* Group: `backup`
* Shell: `/bin/bash` (or another shell capable of running the `borg serve` command)
* Shell: `/bin/bash` (or other capable to run the `borg serve` command)
* Home: `/home/backup`
Most clients should initiate a backup as the root user to capture all
users, groups, and permissions (e.g., when backing up `/home`).
Most clients shall initiate a backup from the root user to catch all
users, groups and permissions (e.g. when backing up `/home`).
Folders
-------
The following directory layout is suggested on the repository server:
The following folder tree layout is suggested on the repository server:
* User home directory, /home/backup
* Repositories path (storage pool): /home/backup/repos
* Clients restricted paths (`/home/backup/repos/<client fqdn>`):
* Clients restricted paths (`/home/backup/repos/<client fqdn>`):
- johndoe.clnt.local: `/home/backup/repos/johndoe.clnt.local`
- web01.srv.local: `/home/backup/repos/web01.srv.local`
@ -68,10 +59,10 @@ but no other directories. You can allow a client to access several separate dire
which could make sense if multiple machines belong to one person which should then have access to all the
backups of their machines.
Only one SSH key per client is allowed. Keys are added for ``johndoe.clnt.local``, ``web01.srv.local`` and
``app01.srv.local``. They will access the backup under a single UNIX user account as
There is only one ssh key per client allowed. Keys are added for ``johndoe.clnt.local``, ``web01.srv.local`` and
``app01.srv.local``. But they will access the backup under only one UNIX user account as:
``backup@backup01.srv.local``. Every key in ``$HOME/.ssh/authorized_keys`` has a
forced command and restrictions applied, as shown below:
forced command and restrictions applied as shown below:
::
@ -81,19 +72,19 @@ forced command and restrictions applied, as shown below:
.. note:: The text shown above needs to be written on a single line!
The options added to the key perform the following:
The options which are added to the key will perform the following:
1. Change working directory
2. Run ``borg serve`` restricted to the client base path
3. Restrict ssh and do not allow stuff which imposes a security risk
Because of the ``cd`` command, the server automatically changes the current
working directory. The client then does not need to know the absolute
Due to the ``cd`` command we use, the server automatically changes the current
working directory. Then client doesn't need to have knowledge of the absolute
or relative remote repository path and can directly access the repositories at
``ssh://<user>@<host>/./<repo>``.
``<user>@<host>:<repo>``.
.. note:: The setup above ignores all client-given command line parameters
that are normally appended to the `borg serve` command.
.. note:: The setup above ignores all client given commandline parameters
which are normally appended to the `borg serve` command.
Client
------
@ -102,21 +93,21 @@ The client needs to initialize the `pictures` repository like this:
::
borg init ssh://backup@backup01.srv.local/./pictures
borg init backup@backup01.srv.local:pictures
Or with the full path (this should not be used in practice; it is only for demonstration purposes).
The server automatically changes the current working directory to the `<client fqdn>` directory.
Or with the full path (should actually never be used, as only for demonstrational purposes).
The server should automatically change the current working directory to the `<client fqdn>` folder.
::
borg init ssh://backup@backup01.srv.local/home/backup/repos/johndoe.clnt.local/pictures
borg init backup@backup01.srv.local:/home/backup/repos/johndoe.clnt.local/pictures
When `johndoe.clnt.local` tries to access a path outside its restriction, the following error is raised.
John Doe tries to back up into the web01 path:
When `johndoe.clnt.local` tries to access a not restricted path the following error is raised.
John Doe tries to backup into the Web 01 path:
::
borg init ssh://backup@backup01.srv.local/home/backup/repos/web01.srv.local/pictures
borg init backup@backup01.srv.local:/home/backup/repos/web01.srv.local/pictures
::
@ -211,7 +202,7 @@ Salt running on a Debian system.
Enhancements
------------
As this section only describes a simple and effective setup, it could be further
As this section only describes a simple and effective setup it could be further
enhanced when supporting (a limited set) of client supplied commands. A wrapper
for starting `borg serve` could be written. Or borg itself could be enhanced to
autodetect it runs under SSH by checking the `SSH_ORIGINAL_COMMAND` environment

View file

@ -5,25 +5,26 @@
Hosting repositories
====================
This section shows how to provide repository storage securely for users.
This sections shows how to securely provide repository storage for users.
Optionally, each user can have a storage quota.
Repositories are accessed through SSH. Each user of the service should
have their own login, which is only able to access that user's files.
Technically, it is possible to have multiple users share one login;
have her own login which is only able to access the user's files.
Technically it would be possible to have multiple users share one login,
however, separating them is better. Separate logins increase isolation
and provide an additional layer of security and safety for both the
and are thus an additional layer of security and safety for both the
provider and the users.
For example, if a user manages to breach ``borg serve``, they can
only damage their own data (assuming that the system does not have further
For example, if a user manages to breach ``borg serve`` then she can
only damage her own data (assuming that the system does not have further
vulnerabilities).
Use the standard directory structure of the operating system. Each user
is assigned a home directory, and that user's repositories reside in their
is assigned a home directory and repositories of the user reside in her
home directory.
The following ``~user/.ssh/authorized_keys`` file is the most important
piece for a correct deployment. It allows the user to log in via
piece for a correct deployment. It allows the user to login via
their public key (which must be provided by the user), and restricts
SSH access to safe operations only.
@ -36,18 +37,18 @@ SSH access to safe operations only.
.. warning::
If this file should be automatically updated (e.g. by a web console),
pay **utmost attention** to sanitizing user input. Strip all whitespace
around the user-supplied key, ensure that it **only** contains ASCII
with no control characters and that it consists of three parts separated
by a single space. Ensure that no newlines are contained within the key.
If this file should be automatically updated (e.g. by a web console),
pay **utmost attention** to sanitizing user input. Strip all whitespace
around the user-supplied key, ensure that it **only** contains ASCII
with no control characters and that it consists of three parts separated
by a single space. Ensure that no newlines are contained within the key.
The ``restrict`` keyword enables all restrictions, i.e. disables port, agent
and X11 forwarding, as well as disabling PTY allocation and execution of ~/.ssh/rc.
If any future restriction capabilities are added to authorized_keys
files they will be included in this set.
The ``command`` keyword forces execution of the specified command
The ``command`` keyword forces execution of the specified command line
upon login. This must be ``borg serve``. The ``--restrict-to-repository``
option permits access to exactly **one** repository. It can be given
multiple times to permit access to more than one repository.
@ -55,6 +56,30 @@ multiple times to permit access to more than one repository.
The repository may not exist yet; it can be initialized by the user,
which allows for encryption.
**Storage quotas** can be enabled by adding the ``--storage-quota`` option
to the ``borg serve`` command line::
restrict,command="borg serve --storage-quota 20G ..." ...
The storage quotas of repositories are completely independent. If a
client is able to access multiple repositories, each repository
can be filled to the specified quota.
If storage quotas are used, ensure that all deployed Borg releases
support storage quotas.
Refer to :ref:`internals_storage_quota` for more details on storage quotas.
**Specificities: Append-only repositories**
Running ``borg init`` via a ``borg serve --append-only`` server will **not**
create a repository that is configured to be append-only by its repository
config.
But, ``--append-only`` arguments in ``authorized_keys`` will override the
repository config, therefore append-only mode can be enabled on a key by key
basis.
Refer to the `sshd(8) <https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man8/sshd.8>`_
man page for more details on SSH options.
See also :ref:`borg_serve`

View file

@ -6,17 +6,17 @@ Backing up entire disk images
Backing up disk images can still be efficient with Borg because its `deduplication`_
technique makes sure only the modified parts of the file are stored. Borg also has
optional simple sparse file support for extraction.
optional simple sparse file support for extract.
It is of utmost importance to pin down the disk you want to back up.
Use the disk's SERIAL for that.
Use:
It is of utmost importancy to pin down the disk you want to backup.
You need to use the SERIAL for that.
Use:
.. code-block:: bash
# You can find the short disk serial by:
# udevadm info --query=property --name=nvme1n1 | grep ID_SERIAL_SHORT | cut -d '=' -f 2
export BORG_REPO=/path/to/repo
DISK_SERIAL="7VS0224F"
DISK_ID=$(readlink -f /dev/disk/by-id/*"${DISK_SERIAL}") # Returns /dev/nvme1n1
@ -25,11 +25,11 @@ Use:
echo "${PARTITIONS[@]}"
echo "Disk Identifier: $DISK_ID"
# Use the following line to perform a Borg backup for the full disk:
# borg create --read-special disk-backup "$DISK_ID"
# Use the following line to perform a borg backup for the full disk:
# borg create --read-special /path/to/repo::{now} "$DISK_ID"
# Use the following to perform a Borg backup for all partitions of the disk
# borg create --read-special partitions-backup "${PARTITIONS[@]}"
# Use the following to perform a borg backup for all partitions of the disk
# borg create --read-special /path/to/repo::{now} "${PARTITIONS[@]}"
# Example output:
# Partitions of /dev/nvme1n1:
@ -37,17 +37,14 @@ Use:
# /dev/nvme1n1p2
# /dev/nvme1n1p3
# Disk Identifier: /dev/nvme1n1
# borg create --read-special disk-backup /dev/nvme1n1
# borg create --read-special partitions-backup /dev/nvme1n1p1 /dev/nvme1n1p2 /dev/nvme1n1p3
# borg create --read-special /path/to/repo::{now} /dev/nvme1n1
# borg create --read-special /path/to/repo::{now} /dev/nvme1n1p1 /dev/nvme1n1p2 /dev/nvme1n1p3
Decreasing the size of image backups
------------------------------------
Disk images are as large as the full disk when uncompressed and might not get much
smaller post-deduplication after heavy use because virtually all filesystems do not
smaller post-deduplication after heavy use because virtually all file systems don't
actually delete file data on disk but instead delete the filesystem entries referencing
the data. Therefore, if a disk nears capacity and files are deleted again, the change
will barely decrease the space it takes up when compressed and deduplicated. Depending
@ -63,28 +60,28 @@ deduplicating. For backup, save the disk header and the contents of each partiti
HEADER_SIZE=$(sfdisk -lo Start $DISK | grep -A1 -P 'Start$' | tail -n1 | xargs echo)
PARTITIONS=$(sfdisk -lo Device,Type $DISK | sed -e '1,/Device\s*Type/d')
dd if=$DISK count=$HEADER_SIZE | borg create --repo repo hostname-partinfo -
dd if=$DISK count=$HEADER_SIZE | borg create repo::hostname-partinfo -
echo "$PARTITIONS" | grep NTFS | cut -d' ' -f1 | while read x; do
PARTNUM=$(echo $x | grep -Eo "[0-9]+$")
ntfsclone -so - $x | borg create --repo repo hostname-part$PARTNUM -
ntfsclone -so - $x | borg create repo::hostname-part$PARTNUM -
done
# to back up non-NTFS partitions as well:
# to backup non-NTFS partitions as well:
echo "$PARTITIONS" | grep -v NTFS | cut -d' ' -f1 | while read x; do
PARTNUM=$(echo $x | grep -Eo "[0-9]+$")
borg create --read-special --repo repo hostname-part$PARTNUM $x
borg create --read-special repo::hostname-part$PARTNUM $x
done
Restoration is a similar process::
borg extract --stdout --repo repo hostname-partinfo | dd of=$DISK && partprobe
borg extract --stdout repo::hostname-partinfo | dd of=$DISK && partprobe
PARTITIONS=$(sfdisk -lo Device,Type $DISK | sed -e '1,/Device\s*Type/d')
borg list --format {archive}{NL} repo | grep 'part[0-9]*$' | while read x; do
PARTNUM=$(echo $x | grep -Eo "[0-9]+$")
PARTITION=$(echo "$PARTITIONS" | grep -E "$DISKp?$PARTNUM" | head -n1)
if echo "$PARTITION" | cut -d' ' -f2- | grep -q NTFS; then
borg extract --stdout --repo repo $x | ntfsclone -rO $(echo "$PARTITION" | cut -d' ' -f1) -
borg extract --stdout repo::$x | ntfsclone -rO $(echo "$PARTITION" | cut -d' ' -f1) -
else
borg extract --stdout --repo repo $x | dd of=$(echo "$PARTITION" | cut -d' ' -f1)
borg extract --stdout repo::$x | dd of=$(echo "$PARTITION" | cut -d' ' -f1)
fi
done
@ -105,18 +102,18 @@ except it works in place, zeroing the original partition. This makes the backup
a bit simpler::
sfdisk -lo Device,Type $DISK | sed -e '1,/Device\s*Type/d' | grep Linux | cut -d' ' -f1 | xargs -n1 zerofree
borg create --read-special --repo repo hostname-disk $DISK
borg create --read-special repo::hostname-disk $DISK
Because the partitions were zeroed in place, restoration is only one command::
borg extract --stdout --repo repo hostname-disk | dd of=$DISK
borg extract --stdout repo::hostname-disk | dd of=$DISK
.. note:: The "traditional" way to zero out space on a partition, especially one already
mounted, is simply to ``dd`` from ``/dev/zero`` to a temporary file and delete
mounted, is to simply ``dd`` from ``/dev/zero`` to a temporary file and delete
it. This is ill-advised for the reasons mentioned in the ``zerofree`` man page:
- it is slow.
- it makes the disk image (temporarily) grow to its maximal extent.
- it is slow
- it makes the disk image (temporarily) grow to its maximal extent
- it (temporarily) uses all free space on the disk, so other concurrent write actions may fail.
Virtual machines
@ -129,7 +126,7 @@ regular file to Borg with the same issues as regular files when it comes to conc
reading and writing from the same file.
For backing up live VMs use filesystem snapshots on the VM host, which establishes
crash-consistency for the VM images. This means that with most filesystems (that
crash-consistency for the VM images. This means that with most file systems (that
are journaling) the FS will always be fine in the backup (but may need a journal
replay to become accessible).
@ -145,10 +142,10 @@ to reach application-consistency; it's a broad and complex issue that cannot be
in entirety here.
Hypervisor snapshots capturing most of the VM's state can also be used for backups and
can be a better alternative to pure filesystem-based snapshots of the VM's disk, since
can be a better alternative to pure file system based snapshots of the VM's disk, since
no state is lost. Depending on the application this can be the easiest and most reliable
way to create application-consistent backups.
Borg does not intend to address these issues due to their huge complexity and
Borg doesn't intend to address these issues due to their huge complexity and
platform/software dependency. Combining Borg with the mechanisms provided by the platform
(snapshots, hypervisor features) will be the best approach to start tackling them.

View file

@ -1,66 +0,0 @@
.. include:: ../global.rst.inc
.. highlight:: none
.. _non_root_user:
================================
Backing up using a non-root user
================================
This section describes how to run Borg as a non-root user and still be able to
back up every file on the system.
Normally, Borg is run as the root user to bypass all filesystem permissions and
be able to read all files. However, in theory this also allows Borg to modify or
delete files on your system (for example, in case of a bug).
To eliminate this possibility, we can run Borg as a non-root user and give it read-only
permissions to all files on the system.
Using Linux capabilities inside a systemd service
=================================================
One way to do so is to use Linux `capabilities
<https://man7.org/linux/man-pages/man7/capabilities.7.html>`_ within a systemd
service.
Linux capabilities allow us to grant parts of the root users privileges to
a non-root user. This works on a per-thread level and does not grant permissions
to the non-root user as a whole.
For this, we need to run the backup script from a systemd service and use the `AmbientCapabilities
<https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#AmbientCapabilities=>`_
option added in systemd 229.
A very basic unit file would look like this:
::
[Unit]
Description=Borg Backup
[Service]
Type=oneshot
User=borg
ExecStart=/usr/local/sbin/backup.sh
AmbientCapabilities=CAP_DAC_READ_SEARCH
The ``CAP_DAC_READ_SEARCH`` capability gives Borg read-only access to all files and directories on the system.
This service can then be started manually using ``systemctl start``, a systemd timer or other methods.
Restore considerations
======================
Use the root user when restoring files. If you use the non-root user, ``borg extract`` will
change ownership of all restored files to the non-root user. Using ``borg mount`` will not allow the
non-root user to access files it would not be able to access on the system itself.
Other than that, you can use the same restore process you would use when running the backup as root.
.. warning::
When using a local repository and running Borg commands as root, make sure to use only commands that do not
modify the repository itself, such as extract or mount. Modifying the repository as root will break it for the
non-root user, since some files inside the repository will then be owned by root.

View file

@ -6,64 +6,56 @@
Backing up in pull mode
=======================
Typically the Borg client connects to a backup server using SSH as a transport
Typically the borg client connects to a backup server using SSH as a transport
when initiating a backup. This is referred to as push mode.
However, if you require the backup server to initiate the connection, or prefer
If you however require the backup server to initiate the connection or prefer
it to initiate the backup run, one of the following workarounds is required to
allow such a pull-mode setup.
allow such a pull mode setup.
A common use case for pull mode is to back up a remote server to a local personal
A common use case for pull mode is to backup a remote server to a local personal
computer.
SSHFS
=====
Assume you have a pull backup system set up with Borg, where a backup server
pulls data from the target via SSHFS. In this mode, the backup client's filesystem
is mounted remotely on the backup server. Pull mode is even possible if
Assuming you have a pull backup system set up with borg, where a backup server
pulls the data from the target via SSHFS. In this mode, the backup client's file
system is mounted remotely on the backup server. Pull mode is even possible if
the SSH connection must be established by the client via a remote tunnel. Other
network file systems like NFS or SMB could be used as well, but SSHFS is very
simple to set up and probably the most secure one.
There are some restrictions caused by SSHFS. For example, unless you define UID
and GID mappings when mounting via ``sshfs``, owners and groups of the mounted
filesystem will probably change, and you may not have access to those files if
Borg is not run with root privileges.
file system will probably change, and you may not have access to those files if
BorgBackup is not run with root privileges.
SSHFS is a FUSE filesystem and uses the SFTP protocol, so there may also be
unsupported features that the actual implementations of SSHFS, libfuse, and
SFTP on the backup server do not support, like filename encodings, ACLs, xattrs,
or flags. Therefore, there is no guarantee that you can restore a system
SSHFS is a FUSE file system and uses the SFTP protocol, so there may be also
other unsupported features that the actual implementations of sshfs, libfuse and
sftp on the backup server do not support, like file name encodings, ACLs, xattrs
or flags. So there is no guarantee that you are able to restore a system
completely in every aspect from such a backup.
.. warning::
To mount the client's root filesystem you will need root access to the
client. This contradicts the usual threat model of Borg, where
clients do not need to trust the backup server (data is encrypted). In pull
To mount the client's root file system you will need root access to the
client. This contradicts to the usual threat model of BorgBackup, where
clients don't need to trust the backup server (data is encrypted). In pull
mode the server (when logged in as root) could cause unlimited damage to the
client. Therefore, pull mode should be used only with servers you fully
client. Therefore, pull mode should be used only from servers you do fully
trust!
.. warning::
Additionally, while chrooted into the client's root filesystem,
code from the client will be executed. Therefore, you should do this only when
you fully trust the client.
.. warning::
The SSHFS + chroot method requires that the backup server and the client
use the same CPU architecture (e.g. both x86_64), as binaries from the
client (like ``/bin/sh`` or the ``borg`` binary) are executed on the
backup server. If you have different architectures, use the :ref:`socat_method`
instead.
Additionally, while being chrooted into the client's root file system,
code from the client will be executed. Thus, you should only do that when
fully trusting the client.
.. warning::
The chroot method was chosen to get the right user and group name-id
mappings, assuming they only come from files (/etc/passwd and /etc/group).
mappings, assuming they only come from files (/etc/passwd and group).
This assumption might be wrong, e.g. if users/groups also come from
ldap or other providers.
Thus, it might be better to use ``--numeric-ids`` and not archive any
@ -106,7 +98,7 @@ create the backup, retaining the original paths, excluding the repository:
::
borg create --exclude borgrepo --files-cache ctime,size --repo /borgrepo archive /
borg create --exclude borgrepo --files-cache ctime,size /borgrepo::archive /
For the sake of simplicity only ``borgrepo`` is excluded here. You may want to
set up an exclude file with additional files and folders to be excluded. Also
@ -167,9 +159,9 @@ Now we can run
::
borg extract --repo /borgrepo archive PATH
borg extract /borgrepo::archive PATH
to restore whatever we like partially. Finally, do the clean-up:
to partially restore whatever we like. Finally, do the clean-up:
::
@ -195,7 +187,7 @@ and extract a backup, utilizing the ``--numeric-ids`` option:
sshfs root@host:/ /mnt/sshfs
cd /mnt/sshfs
borg extract --numeric-ids --repo /path/to/repo archive
borg extract --numeric-ids /path/to/repo::archive
cd ~
umount /mnt/sshfs
@ -207,20 +199,18 @@ directly extract it without the need of mounting with SSHFS:
::
borg export-tar --repo /path/to/repo archive - | ssh root@host 'tar -C / -x'
borg export-tar /path/to/repo::archive - | ssh root@host 'tar -C / -x'
Note that in this scenario the tar format is the limiting factor it cannot
restore all the advanced features that BorgBackup supports. See
:ref:`borg_export-tar` for limitations.
.. _socat_method:
socat
=====
In this setup a SSH connection from the backup server to the client is
established that uses SSH reverse port forwarding to tunnel data
transparently between UNIX domain sockets on the client and server and the socat
established that uses SSH reverse port forwarding to transparently
tunnel data between UNIX domain sockets on the client and server and the socat
tool to connect these with the borg client and server processes, respectively.
The program socat has to be available on the backup server and on the client
@ -257,7 +247,7 @@ to *borg-client* has to have read and write permissions on ``/run/borg``::
On *borg-server*, we have to start the command ``borg serve`` and make its
standard input and output available to a unix socket::
borg-server:~$ socat UNIX-LISTEN:/run/borg/reponame.sock,fork EXEC:"borg serve --restrict-to-path /path/to/repo"
borg-server:~$ socat UNIX-LISTEN:/run/borg/reponame.sock,fork EXEC:"borg serve --append-only --restrict-to-path /path/to/repo"
Socat will wait until a connection is opened. Then socat will execute the
command given, redirecting Standard Input and Output to the unix socket. The
@ -287,7 +277,7 @@ forwarding can do this for us::
Warning: remote port forwarding failed for listen path /run/borg/reponame.sock
When you are done, you have to remove the socket file manually, otherwise
When you are done, you have to manually remove the socket file, otherwise
you may see an error like this when trying to execute borg commands::
Remote: YYYY/MM/DD HH:MM:SS socat[XXX] E connect(5, AF=1 "/run/borg/reponame.sock", 13): Connection refused
@ -311,7 +301,7 @@ ignore all arguments intended for the SSH command.
All Borg commands can now be executed on *borg-client*. For example to create a
backup execute the ``borg create`` command::
borg-client:~$ borg create --repo ssh://borg-server/path/to/repo archive /path_to_backup
borg-client:~$ borg create ssh://borg-server/path/to/repo::archive /path_to_backup
When automating backup creation, the
interactive ssh session may seem inappropriate. An alternative way of creating
@ -322,7 +312,7 @@ a backup may be the following command::
borgc@borg-client \
borg create \
--rsh "sh -c 'exec socat STDIO UNIX-CONNECT:/run/borg/reponame.sock'" \
--repo ssh://borg-server/path/to/repo archive /path_to_backup \
ssh://borg-server/path/to/repo::archive /path_to_backup \
';' rm /run/borg/reponame.sock
This command also automatically removes the socket file after the ``borg
@ -359,15 +349,15 @@ dedicated ssh key:
::
borgs@borg-server$ install -m 700 -d ~/.ssh/
borgs@borg-server$ ssh-keygen -N '' -t rsa -f ~/.ssh/borg-client_key
borgs@borg-server$ { echo -n 'command="borg serve --restrict-to-repo ~/repo",restrict '; cat ~/.ssh/borg-client_key.pub; } >> ~/.ssh/authorized_keys
borgs@borg-server$ ssh-keygen -N '' -t rsa -f ~/.ssh/borg-client_key
borgs@borg-server$ { echo -n 'command="borg serve --append-only --restrict-to-repo ~/repo",restrict '; cat ~/.ssh/borg-client_key.pub; } >> ~/.ssh/authorized_keys
borgs@borg-server$ chmod 600 ~/.ssh/authorized_keys
``install -m 700 -d ~/.ssh/``
Create directory ~/.ssh with correct permissions if it does not exist yet.
``ssh-keygen -N '' -t rsa -f ~/.ssh/borg-client_key``
``ssh-keygen -N '' -t rsa -f ~/.ssh/borg-client_key``
Create an ssh key dedicated to communication with borg-client.
@ -375,10 +365,12 @@ dedicated ssh key:
Another more complex approach is using a unique ssh key for each pull operation.
This is more secure as it guarantees that the key will not be used for other purposes.
``{ echo -n 'command="borg serve --restrict-to-repo ~/repo",restrict '; cat ~/.ssh/borg-client_key.pub; } >> ~/.ssh/authorized_keys``
``{ echo -n 'command="borg serve --append-only --restrict-to-repo ~/repo",restrict '; cat ~/.ssh/borg-client_key.pub; } >> ~/.ssh/authorized_keys``
Add borg-client's ssh public key to ~/.ssh/authorized_keys with forced command and restricted mode.
The borg client is restricted to use one repo at the specified path.
The borg client is restricted to use one repo at the specified path and to append-only operation.
Commands like *delete*, *prune* and *compact* have to be executed another way, for example directly on *borg-server*
side or from a privileged, less restricted client (using another authorized_keys entry).
``chmod 600 ~/.ssh/authorized_keys``
@ -425,88 +417,8 @@ Parentheses are not needed when using a dedicated bash process.
*ssh://borgs@borg-server/~/repo* refers to the repository *repo* within borgs's home directory on *borg-server*.
*StrictHostKeyChecking=no* is used to add host keys automatically to *~/.ssh/known_hosts* without user intervention.
*StrictHostKeyChecking=no* is used to automatically add host keys to *~/.ssh/known_hosts* without user intervention.
``kill "${SSH_AGENT_PID}"``
Kill ssh-agent with loaded keys when it is not needed anymore.
Remote forwarding
=================
The standard ssh client allows to create tunnels to forward local ports to a remote server (local forwarding) and also
to allow remote ports to be forwarded to local ports (remote forwarding).
This remote forwarding can be used to allow remote backup clients to access the backup server even if the backup server
cannot be reached by the backup client.
This can even be used in cases where neither the backup server can reach the backup client and the backup client cannot
reach the backup server, but some intermediate host can access both.
A schematic approach is as follows
::
Backup Server (backup@mybackup) Intermediate Machine (john@myinter) Backup Client (bob@myclient)
1. Establish SSH remote forwarding -----------> SSH listen on local port
2. Starting ``borg create`` establishes
3. SSH forwards to intermediate machine <------- SSH connection to the local port
4. Receives backup connection <------- and further on to backup server
via SSH
So for the backup client the backup is done via SSH to a local port and for the backup server there is a normal backup
performed via ssh.
In order to achieve this, the following commands can be used to create the remote port forwarding:
1. On machine ``myinter``
``ssh bob@myclient -v -C -R 8022:mybackup:22 -N``
This will listen for ssh-connections on port ``8022`` on ``myclient`` and forward connections to port 22 on ``mybackup``.
You can also remove the need for machine ``myinter`` and create the port forwarding on the backup server directly by
using ``localhost`` instead of ``mybackup``
2. On machine ``myclient``
``borg create -v --progress --stats ssh://backup@localhost:8022/home/backup/repos/myclient /``
Make sure to use port ``8022`` and ``localhost`` for the repository as this instructs borg on ``myclient`` to use the
remote forwarded ssh connection.
SSH Keys
--------
If you want to automate backups when using this method, the ssh ``known_hosts`` and ``authorized_keys`` need to be set up
to allow connections.
Security Considerations
-----------------------
Opening up SSH access this way can pose a security risk as it effectively opens remote access to your
backup server on the client even if it is located outside of your company network.
To reduce the chances of compromise, you should configure a forced command in ``authorized_keys`` to prevent
anyone from performing any other action on the backup server.
This can be done e.g. by adding the following in ``$HOME/.ssh/authorized_keys`` on ``mybackup`` with proper
path and client-fqdn:
::
command="cd /home/backup/repos/<client fqdn>;borg serve --restrict-to-path /home/backup/repos/<client fqdn>"
All the additional security considerations for borg should be applied, see :ref:`central-backup-server` for some additional
hints.
More information
----------------
See `remote forwarding`_ and the `ssh man page`_ for more information about remote forwarding.
.. _remote forwarding: https://linuxize.com/post/how-to-setup-ssh-tunneling/
.. _ssh man page: https://manpages.debian.org/testing/manpages-de/ssh.1.de.html

View file

@ -8,7 +8,7 @@ Development
This chapter will get you started with Borg development.
Borg is written in Python (with a little bit of Cython and C for
the performance-critical parts).
the performance critical parts).
Contributions
-------------
@ -19,7 +19,7 @@ Some guidance for contributors:
- Discuss changes on the GitHub issue tracker, on IRC or on the mailing list.
- Make your PRs on the ``master`` branch (see `Branching Model`_ for details and exceptions).
- Make your PRs on the ``master`` branch (see `Branching Model`_ for details).
- Do clean changesets:
@ -52,14 +52,14 @@ Borg development happens on the ``master`` branch and uses GitHub pull
requests (if you don't have GitHub or don't want to use it you can
send smaller patches via the borgbackup mailing list to the maintainers).
Stable releases are maintained on maintenance branches named ``x.y-maint``, e.g.,
the maintenance branch of the 1.4.x series is ``1.4-maint``.
Stable releases are maintained on maintenance branches named ``x.y-maint``, eg.
the maintenance branch of the 1.0.x series is ``1.0-maint``.
Most PRs should be filed against the ``master`` branch. Only if an
issue affects **only** a particular maintenance branch a PR should be
filed against it directly.
While discussing/reviewing a PR it will be decided whether the
While discussing / reviewing a PR it will be decided whether the
change should be applied to maintenance branches. Each maintenance
branch has a corresponding *backport/x.y-maint* label, which will then
be applied.
@ -105,110 +105,11 @@ were collected:
Previously (until release 1.0.10) Borg used a `"merge upwards"
<https://git-scm.com/docs/gitworkflows#_merging_upwards>`_ model where
most minor changes and fixes were committed to a maintenance branch
(e.g. 1.0-maint), and the maintenance branch(es) were regularly merged
most minor changes and fixes where committed to a maintenance branch
(eg. 1.0-maint), and the maintenance branch(es) were regularly merged
back into the main development branch. This became more and more
troublesome due to merges growing more conflict-heavy and error-prone.
How to submit a pull request
----------------------------
In order to contribute to Borg, you will need to fork the ``borgbackup/borg``
main repository to your own Github repository. Then clone your Github repository
to your local machine. The instructions for forking and cloning a repository
can be found there:
`<https://docs.github.com/en/get-started/quickstart/fork-a-repo>`_ .
Make sure you also fetched the git tags, because without them, ``setuptools-scm``
will run into issues determining the correct borg version. Check if ``git tag``
shows a lot of release tags (version numbers).
If it does not, use ``git fetch --tags`` to fetch them.
To work on your contribution, you first need to decide which branch your pull
request should be against. Often, this might be master branch (esp. for big /
risky contributions), but it could be also a maintenance branch like e.g.
1.4-maint (esp. for small fixes that should go into next maintenance release,
e.g. 1.4.x).
Start by checking out the appropriate branch:
::
git checkout master
It is best practice for a developer to keep local ``master`` branch as an
up-to-date copy of the upstream ``master`` branch and always do own work in a
separate feature or bugfix branch.
This is useful to be able to rebase own branches onto the upstream branches
they were branched from, if necessary.
This also applies to other upstream branches (like e.g. ``1.4-maint``), not
only to ``master``.
Thus, create a new branch now:
::
git checkout -b MYCONTRIB-master # choose an appropriate own branch name
Now, work on your contribution in that branch. Use these git commands:
::
git status # is there anything that needs to be added?
git add ... # if so, add it
git commit # finally, commit it. use a descriptive comment.
Then push the changes to your Github repository:
::
git push --set-upstream origin MYCONTRIB-master
Finally, make a pull request on ``borgbackup/borg`` Github repository against
the appropriate branch (e.g. ``master``) so that your changes can be reviewed.
What to do if work was accidentally started in wrong branch
-----------------------------------------------------------
If you accidentally worked in ``master`` branch, check out the ``master``
branch and make sure there are no uncommitted changes. Then, create a feature
branch from that, so that your contribution is in a feature branch.
::
git checkout master
git checkout -b MYCONTRIB-master
Next, check out the ``master`` branch again. Find the commit hash of the last
commit that was made before you started working on your contribution and perform
a hard reset.
::
git checkout master
git log
git reset --hard THATHASH
Then, update the local ``master`` branch with changes made in the upstream
repository.
::
git pull borg master
Rebase feature branch onto updated master branch
------------------------------------------------
After updating the local ``master`` branch from upstream, the feature branch
can be checked out and rebased onto (the now up-to-date) ``master`` branch.
::
git checkout MYCONTRIB-master
git rebase -i master
Next, check if there are any commits that exist in the feature branch
but not in the ``master`` branch and vice versa. If there are no
conflicts or after resolving them, push your changes to your Github repository.
::
git log
git diff master
git push -f
Code and issues
---------------
@ -218,28 +119,14 @@ Code is stored on GitHub, in the `Borgbackup organization
<https://github.com/borgbackup/borg/pulls>`_ should be sent there as
well. See also the :ref:`support` section for more details.
Style guide / Automated Code Formatting
---------------------------------------
Style guide
-----------
We use `black`_ for automatically formatting the code.
If you work on the code, it is recommended that you run black **before each commit**
(so that new code is always using the desired formatting and no additional commits
are required to fix the formatting).
::
pip install -r requirements.d/codestyle.txt # everybody use same black version
black --check . # only check, don't change
black . # reformat the code
The CI workflows will check the code formatting and will fail if it is not formatted correctly.
When (mass-)reformatting existing code, we need to avoid ruining `git blame`, so please
follow their `guide about avoiding ruining git blame`_:
.. _black: https://black.readthedocs.io/
.. _guide about avoiding ruining git blame: https://black.readthedocs.io/en/stable/guides/introducing_black_to_your_project.html#avoiding-ruining-git-blame
We generally follow `pep8
<https://www.python.org/dev/peps/pep-0008/>`_, with 120 columns
instead of 79. We do *not* use form-feed (``^L``) characters to
separate sections either. Compliance is tested automatically when
you run the tests.
Continuous Integration
----------------------
@ -271,15 +158,16 @@ First, just install borg into a virtual env :ref:`as described before <git-insta
To install some additional packages needed for running the tests, activate your
virtual env and run::
pip install -r requirements.d/development.lock.txt
pip install -r requirements.d/development.txt
This project utilizes pre-commit to format and lint code before it is committed.
This project utilizes pre-commit to lint code before it is committed.
Although pre-commit is installed when running the command above, the pre-commit hooks
will have to be installed separately. Run this command to install the pre-commit hooks::
pre-commit install
Running the tests
-----------------
@ -287,7 +175,7 @@ The tests are in the borg/testsuite package.
To run all the tests, you need to have fakeroot installed. If you do not have
fakeroot, you still will be able to run most tests, just leave away the
``fakeroot -u`` from the given command lines.
`fakeroot -u` from the given command lines.
To run the test suite use the following command::
@ -298,7 +186,7 @@ Some more advanced examples::
# verify a changed tox.ini (run this after any change to tox.ini):
fakeroot -u tox --recreate
fakeroot -u tox -e py313 # run all tests, but only on python 3.13
fakeroot -u tox -e py38 # run all tests, but only on python 3.8
fakeroot -u tox borg.testsuite.locking # only run 1 test module
@ -310,34 +198,6 @@ Important notes:
- When using ``--`` to give options to py.test, you MUST also give ``borg.testsuite[.module]``.
Running pytest directly without tox:
::
# run the tests, with parallelism, skipping remote tests
pytest -v -rs --benchmark-skip -n auto -k "not remote"
# run the tests, skipping remote tests, only running repository test
pytest -v -rs --benchmark-skip -k "not remote and repository"
Running the tests (using the pypi package)
------------------------------------------
It is also possible to run the tests without a development environment, using
the borgbackup dist package (downloaded from pypi.org or github releases page):
::
# optional: create and use a virtual env:
python3 -m venv env
. env/bin/activate
# install packages
pip install borgbackup
pip install pytest pytest-benchmark
# run the tests
pytest -v -rs --benchmark-skip --pyargs borg.testsuite
Adding a compression algorithm
------------------------------
@ -360,8 +220,8 @@ for easier use by packagers downstream.
When a command is added, a command line flag changed, added or removed,
the usage docs need to be rebuilt as well::
python scripts/make.py build_usage
python scripts/make.py build_man
python setup.py build_usage
python setup.py build_man
However, we prefer to do this as part of our :ref:`releasing`
preparations, so it is generally not necessary to update these when
@ -415,59 +275,24 @@ Usage::
# To copy files from the VM (in this case, the generated binary):
vagrant scp OS:/vagrant/borg/borg.exe .
Using Podman
------------
macOS-based developers (and others who prefer containers) can run the Linux test suite locally using Podman.
Prerequisites:
- Install Podman (e.g., ``brew install podman``).
- Initialize the Podman machine, only once: ``podman machine init``.
- Start the Podman machine, before using it: ``podman machine start``.
Usage::
# Open an interactive shell in the container (default if no command given):
./scripts/linux-run
# Run the default tox environment:
./scripts/linux-run tox
# Run a specific tox environment:
./scripts/linux-run tox -e py311-pyfuse3
# Pass arguments to pytest (e.g., run specific tests):
./scripts/linux-run tox -e py313-pyfuse3 -- -k mount
# Switch base image (temporarily):
./scripts/linux-run --image python:3.11-bookworm tox
Resource Usage
~~~~~~~~~~~~~~
The default Podman VM uses 2GB RAM and half your CPUs.
For heavy tests (parallel execution), this might be tight.
- **Check usage:** Run ``podman stats`` in another terminal while tests are running.
- **Increase resources:**
::
podman machine stop
podman machine set --cpus 6 --memory 4096
podman machine start
Creating standalone binaries
----------------------------
Make sure you have everything built and installed (including fuse stuff).
When using the Vagrant VMs, pyinstaller will already be installed.
With virtual env activated::
scripts/build-borg-using-pyinstaller.sh
scripts/build-borg-using-nuitka.sh
pip install pyinstaller # or git checkout master
pyinstaller -F -n borg-PLATFORM borg/__main__.py
for file in dist/borg-*; do gpg --armor --detach-sign $file; done
If you encounter issues, see also our `Vagrantfile` for details.
.. note:: Standalone binaries built with pyinstaller are supposed to
work on same OS, same architecture (x86 32bit, amd64 64bit)
without external dependencies.
.. _releasing:
@ -485,18 +310,12 @@ Checklist:
- Update ``CHANGES.rst``, based on ``git log $PREVIOUS_RELEASE..``.
- Check version number of upcoming release in ``CHANGES.rst``.
- Render ``CHANGES.rst`` via ``make html`` and check for markup errors.
- Verify that ``MANIFEST.in``, ``pyproject.toml`` and ``setup.py`` are complete.
- Run these commands, check git status for files that might need to be added, and commit::
python scripts/make.py build_usage
python scripts/make.py build_man
- Verify that ``MANIFEST.in`` and ``setup.py`` are complete.
- ``python setup.py build_usage ; python setup.py build_man`` and commit.
- Tag the release::
git tag -s -m "tagged/signed release X.Y.Z" X.Y.Z
- Push the release PR branch to GitHub, make a pull request.
- Also push the release tag.
- Create a clean repo and use it for the following steps::
git clone borg borg-clean
@ -505,9 +324,8 @@ Checklist:
It will also reveal uncommitted required files.
Moreover, it makes sure the vagrant machines only get committed files and
do a fresh start based on that.
- Optional: run tox and/or binary builds on all supported platforms via vagrant,
check for test failures. This is now optional as we do platform testing and
binary building on GitHub.
- Run tox and/or binary builds on all supported platforms via vagrant,
check for test failures.
- Create sdist, sign it, upload release to (test) PyPi:
::
@ -518,29 +336,27 @@ Checklist:
Note: the signature is not uploaded to PyPi any more, but we upload it to
github releases.
- When GitHub CI looks good on the release PR, merge it and then check "Actions":
GitHub will create binary assets after the release PR is merged within the
CI testing of the merge. Check the "Upload binaries" step on Ubuntu (AMD/Intel
and ARM64) and macOS (Intel and ARM64), fetch the ZIPs with the binaries.
- Unpack the ZIPs and test the binaries, upload the binaries to the GitHub
release page (borg-OS-SPEC-ARCH-gh and borg-OS-SPEC-ARCH-gh.tgz).
- Put binaries into dist/borg-OSNAME and sign them:
::
scripts/sign-binaries 201912312359
- Close the release milestone on GitHub.
- `Update borgbackup.org
<https://github.com/borgbackup/borgbackup.github.io/pull/53/files>`_ with the
new version number and release date.
- Announce on:
- Mailing list.
- Mastodon / BlueSky / X (aka Twitter).
- IRC channel (change ``/topic``).
- Mailing list.
- Twitter.
- IRC channel (change ``/topic``).
- Create a GitHub release, include:
- pypi dist package and signature
- Standalone binaries (see above for how to create them).
* pypi dist package and signature
* Standalone binaries (see above for how to create them).
- For macOS binaries **with** FUSE support, document the macFUSE version
in the README of the binaries. macFUSE uses a kernel extension that needs
to be compatible with the code contained in the binary.
- A link to ``CHANGES.rst``.
+ For macOS, document the macFUSE version in the README of the binaries.
macFUSE uses a kernel extension that needs to be compatible with the
code contained in the binary.
* A link to ``CHANGES.rst``.

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
.. highlight:: bash
.. |package_dirname| replace:: borgbackup-|version|
.. |package_filename| replace:: |package_dirname|.tar.gz
.. |package_url| replace:: https://pypi.org/project/borgbackup/#files
.. |package_url| replace:: https://pypi.python.org/packages/source/b/borgbackup/|package_filename|
.. |git_url| replace:: https://github.com/borgbackup/borg.git
.. _github: https://github.com/borgbackup/borg
.. _issue tracker: https://github.com/borgbackup/borg/issues
@ -10,20 +10,20 @@
.. _HMAC-SHA256: https://en.wikipedia.org/wiki/HMAC
.. _SHA256: https://en.wikipedia.org/wiki/SHA-256
.. _PBKDF2: https://en.wikipedia.org/wiki/PBKDF2
.. _argon2: https://en.wikipedia.org/wiki/Argon2
.. _ACL: https://en.wikipedia.org/wiki/Access_control_list
.. _libacl: https://savannah.nongnu.org/projects/acl/
.. _libattr: https://savannah.nongnu.org/projects/attr/
.. _liblz4: https://github.com/Cyan4973/lz4
.. _libzstd: https://github.com/facebook/zstd
.. _libb2: https://github.com/BLAKE2/libb2
.. _OpenSSL: https://www.openssl.org/
.. _`Python 3`: https://www.python.org/
.. _Buzhash: https://en.wikipedia.org/wiki/Buzhash
.. _msgpack: https://msgpack.org/
.. _`msgpack-python`: https://pypi.org/project/msgpack-python/
.. _llfuse: https://pypi.org/project/llfuse/
.. _mfusepy: https://pypi.org/project/mfusepy/
.. _pyfuse3: https://pypi.org/project/pyfuse3/
.. _`msgpack-python`: https://pypi.python.org/pypi/msgpack-python/
.. _llfuse: https://pypi.python.org/pypi/llfuse/
.. _pyfuse3: https://pypi.python.org/pypi/pyfuse3/
.. _userspace filesystems: https://en.wikipedia.org/wiki/Filesystem_in_Userspace
.. _Cython: https://cython.org/
.. _virtualenv: https://pypi.org/project/virtualenv/
.. _Cython: http://cython.org/
.. _virtualenv: https://pypi.python.org/pypi/virtualenv/
.. _mailing list discussion about internals: http://librelist.com/browser/attic/2014/5/6/questions-and-suggestions-about-inner-working-of-attic>

View file

@ -6,7 +6,7 @@ Borg Documentation
.. include:: ../README.rst
.. When you add an element here, do not forget to add it to book.rst.
.. when you add an element here, do not forget to add it to book.rst
.. toctree::
:maxdepth: 2
@ -18,8 +18,6 @@ Borg Documentation
faq
support
changes
changes_1.x
changes_0.x
internals
development
authors

View file

@ -13,7 +13,6 @@ There are different ways to install Borg:
that comes bundled with all dependencies.
- :ref:`source-install`, either:
- :ref:`windows-binary` - builds a binary file for Windows using MSYS2.
- :ref:`pip-installation` - installing a source package with pip needs
more installation steps and requires all dependencies with
development headers and a compiler.
@ -43,7 +42,7 @@ package which can be installed with the package manager.
Distribution Source Command
============ ============================================= =======
Alpine Linux `Alpine repository`_ ``apk add borgbackup``
Arch Linux `[extra]`_ ``pacman -S borg``
Arch Linux `[community]`_ ``pacman -S borg``
Debian `Debian packages`_ ``apt install borgbackup``
Gentoo `ebuild`_ ``emerge borgbackup``
GNU Guix `GNU Guix`_ ``guix package --install borg``
@ -64,14 +63,14 @@ Ubuntu `Ubuntu packages`_, `Ubuntu PPA`_ ``apt install borgbac
============ ============================================= =======
.. _Alpine repository: https://pkgs.alpinelinux.org/packages?name=borgbackup
.. _[extra]: https://www.archlinux.org/packages/?name=borg
.. _[community]: https://www.archlinux.org/packages/?name=borg
.. _Debian packages: https://packages.debian.org/search?keywords=borgbackup&searchon=names&exact=1&suite=all&section=all
.. _Fedora official repository: https://packages.fedoraproject.org/pkgs/borgbackup/borgbackup/
.. _FreeBSD ports: https://www.freshports.org/archivers/py-borgbackup/
.. _ebuild: https://packages.gentoo.org/packages/app-backup/borgbackup
.. _GNU Guix: https://www.gnu.org/software/guix/package-list.html#borg
.. _pkgsrc: https://pkgsrc.se/sysutils/py-borgbackup
.. _cauldron: https://madb.mageia.org/package/show/application/0/release/cauldron/name/borgbackup
.. _pkgsrc: http://pkgsrc.se/sysutils/py-borgbackup
.. _cauldron: http://madb.mageia.org/package/show/application/0/release/cauldron/name/borgbackup
.. _.nix file: https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/backup/borgbackup/default.nix
.. _OpenBSD ports: https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/sysutils/borgbackup/
.. _OpenIndiana hipster repository: https://pkg.openindiana.org/hipster/en/search.shtml?token=borg&action=Search
@ -82,9 +81,9 @@ Ubuntu `Ubuntu packages`_, `Ubuntu PPA`_ ``apt install borgbac
.. _Ubuntu packages: https://launchpad.net/ubuntu/+source/borgbackup
.. _Ubuntu PPA: https://launchpad.net/~costamagnagianfranco/+archive/ubuntu/borgbackup
Please ask package maintainers to build a package or, if you can package/
Please ask package maintainers to build a package or, if you can package /
submit it yourself, please help us with that! See :issue:`105` on
GitHub to follow up on packaging efforts.
github to followup on packaging efforts.
**Current status of package in the repositories**
@ -106,12 +105,12 @@ Standalone Binary
.. note:: Releases are signed with an OpenPGP key, see
:ref:`security-contact` for more instructions.
Borg x86/x64 AMD/Intel compatible binaries (generated with `pyinstaller`_)
Borg x86/x64 amd/intel compatible binaries (generated with `pyinstaller`_)
are available on the releases_ page for the following platforms:
* **Linux**: glibc >= 2.28 (ok for most supported Linux releases).
Older glibc releases are untested and may not work.
* **macOS**: 10.12 or newer (To avoid signing issues, download the file via
* **MacOS**: 10.12 or newer (To avoid signing issues download the file via
command line **or** remove the ``quarantine`` attribute after downloading:
``$ xattr -dr com.apple.quarantine borg-macosx64.tgz``)
* **FreeBSD**: 12.1 (unknown whether it works for older releases)
@ -135,10 +134,10 @@ fail if /tmp has not enough free space or is mounted with the ``noexec``
option. You can change the temporary directory by setting the ``TEMP``
environment variable before running Borg.
If a new version is released, you will have to download it manually and replace
If a new version is released, you will have to manually download it and replace
the old version using the same steps as shown above.
.. _pyinstaller: https://www.pyinstaller.org
.. _pyinstaller: http://www.pyinstaller.org
.. _releases: https://github.com/borgbackup/borg/releases
.. _source-install:
@ -158,30 +157,30 @@ Dependencies
~~~~~~~~~~~~
To install Borg from a source package (including pip), you have to install the
following dependencies first. For the libraries you will also need their
development header files (sometimes in a separate `-dev` or `-devel` package).
following dependencies first:
* `Python 3`_ >= 3.11.0
* OpenSSL_ >= 1.1.1 (LibreSSL will not work)
* libacl_ (which depends on libattr_)
* liblz4_ >= 1.7.0 (r129)
* libffi (required for argon2-cffi-bindings)
* pkg-config (cli tool) - Borg uses this to discover header and library
locations automatically. Alternatively, you can also point to them via some
environment variables, see setup.py.
* Some other Python dependencies, pip will automatically install them for you.
* Optionally, if you wish to mount an archive as a FUSE filesystem, you need
* `Python 3`_ >= 3.8.0, plus development headers.
* OpenSSL_ >= 1.0.0, plus development headers.
* libacl_ (which depends on libattr_), both plus development headers.
* We have bundled code of the following packages, but borg by default (see
setup.py if you want to change that) prefers a shared library if it can
be found on the system (lib + dev headers) at build time:
- liblz4_ >= 1.7.0 (r129)
- libzstd_ >= 1.3.0
- libxxhash >= 0.8.1 (0.8.0 might work also)
* pkg-config (cli tool) and pkgconfig python package (borg uses these to
discover header and library location - if it can't import pkgconfig and
is not pointed to header/library locations via env vars [see setup.py],
it will fall back to using the bundled code, see above).
**These must be present before invoking setup.py!**
* some other Python dependencies, pip will automatically install them for you.
* optionally, if you wish to mount an archive as a FUSE filesystem, you need
a FUSE implementation for Python:
- mfusepy_ >= 3.1.0 (for fuse 2 and fuse 3, use `pip install borgbackup[mfusepy]`), or
- pyfuse3_ >= 3.1.1 (for fuse 3, use `pip install borgbackup[pyfuse3]`), or
- llfuse_ >= 1.3.8 (for fuse 2, use `pip install borgbackup[llfuse]`).
- Additionally, your OS will need to have FUSE support installed
(e.g. a package `fuse` for fuse 2 or a package `fuse3` for fuse 3 support).
* Optionally, if you wish to use S3/B2 Backend:
- borgstore[s3] ~= 0.3.0 (use `pip install borgbackup[s3]`)
* Optionally, if you wish to use SFTP Backend:
- borgstore[sftp] ~= 0.3.0 (use `pip install borgbackup[sftp]`)
- Either pyfuse3_ (preferably, newer and maintained) or llfuse_ (older,
unmaintained now). See also the BORG_FUSE_IMPL env variable.
- See setup.py about the version requirements.
If you have troubles finding the right package names, have a look at the
distribution specific sections below or the Vagrantfile in the git repository,
@ -189,35 +188,24 @@ which contains installation scripts for a number of operating systems.
In the following, the steps needed to install the dependencies are listed for a
selection of platforms. If your distribution is not covered by these
instructions, try to use your package manager to install the dependencies.
instructions, try to use your package manager to install the dependencies. On
FreeBSD, you may need to get a recent enough OpenSSL version from FreeBSD
ports.
After you have installed the dependencies, you can proceed with steps outlined
under :ref:`pip-installation`.
Arch Linux
++++++++++
Install the runtime and build dependencies::
pacman -S python python-pip python-virtualenv openssl acl lz4 base-devel
pacman -S fuse2 # needed for llfuse
pacman -S fuse3 # needed for pyfuse3
Note that Arch Linux specifically doesn't support
`partial upgrades <https://wiki.archlinux.org/title/Partial_upgrade>`__,
so in case some packages cannot be retrieved from the repo, run with ``pacman -Syu``.
Debian / Ubuntu
+++++++++++++++
Install the dependencies with development headers::
sudo apt-get install python3 python3-dev python3-pip python3-virtualenv \
libacl1-dev \
libacl1-dev libacl1 \
libssl-dev \
liblz4-dev \
libffi-dev \
build-essential pkg-config
liblz4-dev libzstd-dev libxxhash-dev \
build-essential \
pkg-config python3-pkgconfig
sudo apt-get install libfuse-dev fuse # needed for llfuse
sudo apt-get install libfuse3-dev fuse3 # needed for pyfuse3
@ -231,11 +219,10 @@ Fedora
Install the dependencies with development headers::
sudo dnf install python3 python3-devel python3-pip python3-virtualenv \
libacl-devel \
libacl-devel libacl \
openssl-devel \
lz4-devel \
libffi-devel \
pkgconf
lz4-devel libzstd-devel xxhash-devel \
pkgconf python3-pkgconfig
sudo dnf install gcc gcc-c++ redhat-rpm-config
sudo dnf install fuse-devel fuse # needed for llfuse
sudo dnf install fuse3-devel fuse3 # needed for pyfuse3
@ -250,8 +237,8 @@ Install the dependencies automatically using zypper::
Alternatively, you can enumerate all build dependencies in the command line::
sudo zypper install python3 python3-devel \
libacl-devel openssl-devel liblz4-devel \
libffi-devel \
libacl-devel openssl-devel \
libxxhash-devel \
python3-Cython python3-Sphinx python3-msgpack-python python3-pkgconfig pkgconf \
python3-pytest python3-setuptools python3-setuptools_scm \
python3-sphinx_rtd_theme gcc gcc-c++
@ -260,10 +247,16 @@ Alternatively, you can enumerate all build dependencies in the command line::
macOS
+++++
When installing borgbackup via Homebrew_, the basic dependencies are installed automatically.
When installing via Homebrew_, dependencies are installed automatically. To install
dependencies manually::
For FUSE support to mount the backup archives, you need macFUSE, which is available
via `github <https://github.com/osxfuse/osxfuse/releases/latest>`__, or Homebrew::
brew install python3 openssl zstd lz4 xxhash
brew install pkg-config
pip3 install virtualenv pkgconfig
For FUSE support to mount the backup archives, you need at least version 3.0 of
macFUSE, which is available via `github
<https://github.com/osxfuse/osxfuse/releases/latest>`__, or Homebrew::
brew install --cask macfuse
@ -273,13 +266,6 @@ the installed ``openssl`` formula, point pkg-config to the correct path::
PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig" pip install borgbackup[llfuse]
When working from a borg git repo workdir, you can install dependencies using the
Brewfile::
brew install python@3.11 # can be any supported python3 version
brew bundle install # install requirements from borg repo's ./Brewfile
pip3 install virtualenv
Be aware that for all recent macOS releases you must authorize full disk access.
It is no longer sufficient to run borg backups as root. If you have not yet
granted full disk access, and you run Borg backup from cron, you will see
@ -301,7 +287,7 @@ and commands to make FUSE work for using the mount command.
pkg install -y python3 pkgconf
pkg install openssl
pkg install liblz4
pkg install liblz4 zstd xxhash
pkg install fusefs-libs # needed for llfuse
pkg install -y git
python3 -m ensurepip # to install pip for Python3
@ -311,43 +297,6 @@ and commands to make FUSE work for using the mount command.
kldload fuse
sysctl vfs.usermount=1
.. _windows_deps:
Windows
+++++++
.. note::
Running under Windows is experimental.
.. warning::
This script needs to be run in the UCRT64 environment in MSYS2.
Install the dependencies with the provided script::
./scripts/msys2-install-deps
.. _msys2_path_translation:
MSYS2 Path Translation
++++++++++++++++++++++
When running Borg within an MSYS2 environment, the shell
automatically translates POSIX-style paths (like ``/tmp`` or ``/C/Users``) to
Windows paths (like ``C:\msys64\tmp`` or ``C:\Users``) before they reach the
Borg process.
This behavior can result in absolute Windows paths being stored in your backups,
which may not be what you intended if you use POSIX paths for portability.
To disable this automatic translation for Borg, you can use environment variables
to exclude everything from conversion. Similarly, MSYS2 also translates
environment variables that look like paths. To disable this generally for Borg,
set both variables::
export MSYS2_ARG_CONV_EXCL="*"
export MSYS2_ENV_CONV_EXCL="*"
For more details, see the `MSYS2 documentation on filesystem paths <https://www.msys2.org/docs/filesystem-paths/>`__.
Windows 10's Linux Subsystem
++++++++++++++++++++++++++++
@ -366,51 +315,28 @@ Cygwin
Use the Cygwin installer to install the dependencies::
python39 python39-devel
python39-setuptools python39-pip python39-wheel python39-virtualenv
libssl-devel liblz4-devel
python38 python38-devel python38-pkgconfig
python38-setuptools python38-pip python38-wheel python38-virtualenv
libssl-devel libxxhash-devel liblz4-devel libzstd-devel
binutils gcc-g++ git make openssh
Make sure to use a virtual environment to avoid confusions with any Python installed on Windows.
.. _windows-binary:
Building a binary on Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::
This is experimental.
.. warning::
This needs to be run in the UCRT64 environment in MSYS2.
Ensure to install the dependencies as described within :ref:`Dependencies: Windows <windows_deps>`.
::
# Needed for setuptools < 70.2.0 to work - https://www.msys2.org/docs/python/#known-issues
# export SETUPTOOLS_USE_DISTUTILS=stdlib
pip install -e .
pyinstaller -y scripts/borg.exe.spec
A standalone executable will be created in ``dist/borg.exe``.
.. _pip-installation:
Using pip
~~~~~~~~~
Ensure to install the dependencies as described within :ref:`source-install`.
Virtualenv_ can be used to build and install Borg without affecting
the system Python or requiring root access. Using a virtual environment is
optional, but recommended except for the most simple use cases.
Ensure to install the dependencies as described within :ref:`source-install`.
.. note::
If you install into a virtual environment, you need to **activate** it
first (``source borg-env/bin/activate``), before running ``borg``.
Alternatively, symlink ``borg-env/bin/borg`` into some directory that is in
your ``PATH`` so you can run ``borg``.
your ``PATH`` so you can just run ``borg``.
This will use ``pip`` to install the latest release from PyPi::
@ -420,6 +346,9 @@ This will use ``pip`` to install the latest release from PyPi::
# might be required if your tools are outdated
pip install -U pip setuptools wheel
# pkgconfig MUST be available before borg is installed!
pip install pkgconfig
# install Borg + Python dependencies into virtualenv
pip install borgbackup
# or alternatively (if you want FUSE support):
@ -449,14 +378,10 @@ locally::
Using git
~~~~~~~~~
This uses latest, unreleased development code from git.
While we try not to break master, there are no guarantees on anything.
Ensure to install the dependencies as described within :ref:`source-install`.
Version metadata is obtained dynamically at install time using ``setuptools-scm``.
Please ensure that your git repo either has correct tags, or provide the version
manually using the ``SETUPTOOLS_SCM_PRETEND_VERSION`` environment variable.
This uses latest, unreleased development code from git.
While we try not to break master, there are no guarantees on anything.
::
@ -467,15 +392,11 @@ manually using the ``SETUPTOOLS_SCM_PRETEND_VERSION`` environment variable.
virtualenv --python=$(which python3) borg-env
source borg-env/bin/activate # always before using!
# install borg dependencies into virtualenv
# install borg + dependencies into virtualenv
cd borg
pip install -r requirements.d/development.lock.txt
pip install -r requirements.d/development.txt
pip install -r requirements.d/docs.txt # optional, to build the docs
# set a borg version if setuptools-scm fails to do so automatically
export SETUPTOOLS_SCM_PRETEND_VERSION=
# install borg into virtualenv
pip install -e . # in-place editable mode
or
pip install -e .[pyfuse3] # in-place editable mode, use pyfuse3
@ -493,11 +414,11 @@ If you need to use a different version of Python you can install this using ``py
...
# create a virtual environment
pyenv install 3.11.0 # minimum, preferably use something more recent!
pyenv global 3.11.0
pyenv local 3.11.0
pyenv install 3.8.0 # minimum, preferably use something more recent!
pyenv global 3.8.0
pyenv local 3.8.0
virtualenv --python=${pyenv which python} borg-env
source borg-env/bin/activate # always before using!
...
.. note:: As a developer or power user, you should always use a virtual environment.
.. note:: As a developer or power user, you always want to use a virtual environment.

View file

@ -4,7 +4,7 @@
Internals
=========
The internals chapter describes and analyzes most of the inner workings
The internals chapter describes and analyses most of the inner workings
of Borg.
Borg uses a low-level, key-value store, the :ref:`repository`, and
@ -19,29 +19,28 @@ specified when the backup was performed.
Deduplication is performed globally across all data in the repository
(multiple backups and even multiple hosts), both on data and file
metadata, using :ref:`chunks` created by the chunker using the
Buzhash_ algorithm ("buzhash" and "buzhash64" chunker) or a simpler
fixed block size algorithm ("fixed" chunker).
Buzhash_ algorithm ("buzhash" chunker) or a simpler fixed blocksize
algorithm ("fixed" chunker).
To perform the repository-wide deduplication, a hash of each
To actually perform the repository-wide deduplication, a hash of each
chunk is checked against the :ref:`chunks cache <cache>`, which is a
hash table of all chunks that already exist.
hash-table of all chunks that already exist.
.. figure:: internals/structure.png
:figwidth: 100%
:width: 100%
Layers in Borg. At the very top, commands are implemented, using
Layers in Borg. On the very top commands are implemented, using
a data access layer provided by the Archive and Item classes.
The "key" object provides both compression and authenticated
encryption used by the data access layer. The "key" object represents
the sole trust boundary in Borg.
The lowest layer is the repository accessed via class Repository.
Repository uses ``borgstore`` internally.
The lowest layer is the repository, either accessed directly
(Repository) or remotely (RemoteRepository).
.. toctree::
:caption: Internals contents
internals/security
internals/data-structures
internals/packs
internals/frontends

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 KiB

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

View file

@ -11,13 +11,16 @@ but does mean that there are no release-to-release guarantees on what you might
even for point releases (1.1.x), and there is no documentation beyond the code and the internals documents.
Borg does on the other hand provide an API on a command-line level. In other words, a frontend should
(for example) create a backup archive by invoking :ref:`borg_create`, provide command-line parameters/options
as needed, and parse JSON output from Borg.
(for example) create a backup archive just invoke :ref:`borg_create`, give commandline parameters/options
as needed and parse JSON output from borg.
Important: JSON output is expected to be UTF-8, but currently borg depends on the locale being configured
for that (must be a UTF-8 locale and *not* "C" or "ascii"), so that Python will choose to encode to UTF-8.
The same applies to any inputs read by borg, they are expected to be UTF-8 encoded also.
We consider this a bug (see :issue:`2273`) and might fix it later, so borg will use UTF-8 independent of
the locale.
On POSIX systems, you can usually set environment vars to choose a UTF-8 locale:
::
@ -26,53 +29,6 @@ On POSIX systems, you can usually set environment vars to choose a UTF-8 locale:
export LC_CTYPE=en_US.UTF-8
Another way to get Python's stdin/stdout/stderr streams to use UTF-8 encoding (without having
a UTF-8 locale / LANG / LC_CTYPE) is:
::
export PYTHONIOENCODING=utf-8
See :issue:`2273` for more details.
Dealing with non-unicode byte sequences and JSON limitations
------------------------------------------------------------
Paths on POSIX systems can have arbitrary bytes in them (except 0x00 which is used as string terminator in C).
Nowadays, UTF-8 encoded paths (which decode to valid unicode) are the usual thing, but a lot of systems
still have paths from the past, when other, non-unicode codings were used. Especially old Samba shares often
have wild mixtures of misc. encodings, sometimes even very broken stuff.
borg deals with such non-unicode paths ("with funny/broken characters") by decoding such byte sequences using
UTF-8 coding and "surrogateescape" error handling mode, which maps invalid bytes to special unicode code points
(surrogate escapes). When encoding such a unicode string back to a byte sequence, the original byte sequence
will be reproduced exactly.
JSON should only contain valid unicode text without any surrogate escapes, so we can't just directly have a
surrogate-escaped path in JSON ("path" is only one example, this also affects other text-like content).
Borg deals with this situation like this (since borg 2.0):
For a valid unicode path (no surrogate escapes), the JSON will only have "path": path.
For a non-unicode path (with surrogate escapes), the JSON will have 2 entries:
- "path": path_approximation (pure valid unicode, all invalid bytes will show up as "?")
- "path_b64": path_bytes_base64_encoded (if you decode the base64, you get the original path byte string)
JSON users need to pick whatever suits their needs best. The suggested procedure (shown for "path") is:
- check if there is a "path_b64" key.
- if it is there, you will know that the original bytes path did not cleanly UTF-8-decode into unicode (has
some invalid bytes) and that the string given by the "path" key is only an approximation, but not the precise
path. if you need precision, you must base64-decode the value of "path_b64" and deal with the arbitrary byte
string you'll get. if an approximation is fine, use the value of the "path" key.
- if it is not there, the value of the "path" key is all you need (the original bytes path is its UTF-8 encoding).
Logging
-------
@ -84,6 +40,8 @@ where each line is a JSON object. The *type* key of the object determines its ot
parsing error will be printed in plain text, because logging set-up happens after all arguments are
parsed.
Since JSON can only encode text, any string representing a file system path may miss non-text parts.
The following types are in use. Progress information is governed by the usual rules for progress information,
it is not produced unless ``--progress`` is specified.
@ -255,7 +213,7 @@ Passphrase prompts should be handled differently. Use the environment variables
and *BORG_NEW_PASSPHRASE* (see :ref:`env_vars` for reference) to pass passphrases to Borg, don't
use the interactive passphrase prompts.
When setting a new passphrase (:ref:`borg_repo-create`, :ref:`borg_key_change-passphrase`) normally
When setting a new passphrase (:ref:`borg_init`, :ref:`borg_key_change-passphrase`) normally
Borg prompts whether it should display the passphrase. This can be suppressed by setting
the environment variable *BORG_DISPLAY_PASSPHRASE* to *no*.
@ -280,7 +238,7 @@ and :ref:`borg_list` implement a ``--json`` option which turns their regular out
Some commands, like :ref:`borg_list` and :ref:`borg_diff`, can produce *a lot* of JSON. Since many JSON implementations
don't support a streaming mode of operation, which is pretty much required to deal with this amount of JSON, these
commands implement a ``--json-lines`` option which generates output in the `JSON lines <https://jsonlines.org/>`_ format,
commands implement a ``--json-lines`` option which generates output in the `JSON lines <http://jsonlines.org/>`_ format,
which is simply a number of JSON objects separated by new lines.
Dates are formatted according to ISO 8601 in local time. No explicit time zone is specified *at this time*
@ -298,12 +256,10 @@ last_modified
The *encryption* key, if present, contains:
encryption
Textual cipher / AE algorithm name (same as :ref:`borg_repo-create` ``--encryption`` names)
id_hash
Textual id hash function name (same as :ref:`borg_repo-create` ``--id-hash`` names)
mode
Textual encryption mode name (same as :ref:`borg_init` ``--encryption`` names)
keyfile
Path to the local key file used for access. Depending on the key location this may be absent.
Path to the local key file used for access. Depending on *mode* this key may be absent.
The *cache* key, if present, contains:
@ -318,8 +274,12 @@ stats
Number of unique chunks
total_size
Total uncompressed size of all chunks multiplied with their reference counts
total_csize
Total compressed and encrypted size of all chunks multiplied with their reference counts
unique_size
Uncompressed size of all chunks
unique_csize
Compressed and encrypted size of all chunks
.. highlight: json
@ -330,14 +290,15 @@ Example *borg info* output::
"path": "/home/user/.cache/borg/0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
"stats": {
"total_chunks": 511533,
"total_csize": 17948017540,
"total_size": 22635749792,
"total_unique_chunks": 54892,
"unique_csize": 1920405405,
"unique_size": 2449675468
}
},
"encryption": {
"encryption": "aes256-ocb",
"id_hash": "sha256"
"mode": "repokey"
},
"repository": {
"id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
@ -376,6 +337,11 @@ stats
Deduplicated size (against the current repository, not when the archive was created)
nfiles
Number of regular files in the archive
limits
Object describing the utilization of Borg limits
max_archive_size
Float between 0 and 1 describing how large this archive is relative to the maximum size allowed by Borg
command_line
Array of strings of the command line that created the archive
@ -413,8 +379,7 @@ Example of a simple archive listing (``borg list --last 1 --json``)::
}
],
"encryption": {
"encryption": "aes256-ocb",
"id_hash": "sha256"
"mode": "repokey"
},
"repository": {
"id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
@ -446,6 +411,9 @@ The same archive with more information (``borg info --last 1 --json``)::
"end": "2017-02-27T12:27:20.789123",
"hostname": "host",
"id": "80cd07219ad725b3c5f665c1dcf119435c4dee1647a560ecac30f8d40221a46a",
"limits": {
"max_archive_size": 0.0001330855110409714
},
"name": "host-system-backup-2017-02-27",
"start": "2017-02-27T12:27:20.789123",
"stats": {
@ -461,14 +429,15 @@ The same archive with more information (``borg info --last 1 --json``)::
"path": "/home/user/.cache/borg/0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
"stats": {
"total_chunks": 511533,
"total_csize": 17948017540,
"total_size": 22635749792,
"total_unique_chunks": 54892,
"unique_csize": 1920405405,
"unique_size": 2449675468
}
},
"encryption": {
"encryption": "aes256-ocb",
"id_hash": "sha256"
"mode": "repokey"
},
"repository": {
"id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
@ -485,15 +454,14 @@ Refer to the *borg list* documentation for the available keys and their meaning.
Example (excerpt) of ``borg list --json-lines``::
{"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux", "target": "", "flags": null, "mtime": "2017-02-27T12:27:20.023407", "size": 0}
{"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux/baz", "target": "", "flags": null, "mtime": "2017-02-27T12:27:20.585407", "size": 0}
{"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux", "healthy": true, "source": "", "linktarget": "", "flags": null, "mtime": "2017-02-27T12:27:20.023407", "size": 0}
{"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux/baz", "healthy": true, "source": "", "linktarget": "", "flags": null, "mtime": "2017-02-27T12:27:20.585407", "size": 0}
Archive Differencing
++++++++++++++++++++
Each archive difference item (file contents, user/group/mode) output by :ref:`borg_diff` is represented by an *ItemDiff* object.
The properties of an *ItemDiff* object are:
The propertiese of an *ItemDiff* object are:
path:
The filename/path of the *Item* (file, directory, symlink).
@ -570,171 +538,92 @@ Message IDs are strings that essentially give a log message or operation a name,
full text, since texts change more frequently. Message IDs are unambiguous and reduce the need to parse
log messages.
Assigned message IDs and related error RCs (exit codes) are:
Assigned message IDs are:
.. See scripts/errorlist.py; this is slightly edited.
Errors
Error rc: 2 traceback: no
Error: {}
ErrorWithTraceback rc: 2 traceback: yes
Error: {}
Buffer.MemoryLimitExceeded rc: 2 traceback: no
Requested buffer size {} is above the limit of {}.
EfficientCollectionQueue.SizeUnderflow rc: 2 traceback: no
Could not pop_front first {} elements, collection only has {} elements..
RTError rc: 2 traceback: no
Runtime Error: {}
CancelledByUser rc: 3 traceback: no
Cancelled by user.
CommandError rc: 4 traceback: no
Command Error: {}
PlaceholderError rc: 5 traceback: no
Formatting Error: "{}".format({}): {}({})
InvalidPlaceholder rc: 6 traceback: no
Invalid placeholder "{}" in string: {}
Repository.AlreadyExists rc: 10 traceback: no
A repository already exists at {}.
Repository.CheckNeeded rc: 12 traceback: yes
Inconsistency detected. Please run "borg check {}".
Repository.DoesNotExist rc: 13 traceback: no
Repository {} does not exist.
Repository.InsufficientFreeSpaceError rc: 14 traceback: no
Insufficient free space to complete transaction (required: {}, available: {}).
Repository.InvalidRepository rc: 15 traceback: no
{} is not a valid repository. Check repo config.
Repository.InvalidRepositoryConfig rc: 16 traceback: no
{} does not have a valid configuration. Check repo config [{}].
Repository.ObjectNotFound rc: 17 traceback: yes
Object with key {} not found in repository {}.
Repository.ParentPathDoesNotExist rc: 18 traceback: no
The parent path of the repo directory [{}] does not exist.
Repository.PathAlreadyExists rc: 19 traceback: no
There is already something at {}.
Repository.PathPermissionDenied rc: 21 traceback: no
Permission denied to {}.
MandatoryFeatureUnsupported rc: 25 traceback: no
Unsupported repository feature(s) {}. A newer version of borg is required to access this repository.
NoManifestError rc: 26 traceback: no
Repository has no manifest.
UnsupportedManifestError rc: 27 traceback: no
Unsupported manifest envelope. A newer version is required to access this repository.
Archive.AlreadyExists rc: 30 traceback: no
Archive.AlreadyExists
Archive {} already exists
Archive.DoesNotExist rc: 31 traceback: no
Archive.DoesNotExist
Archive {} does not exist
Archive.IncompatibleFilesystemEncodingError rc: 32 traceback: no
Archive.IncompatibleFilesystemEncodingError
Failed to encode filename "{}" into file system encoding "{}". Consider configuring the LANG environment variable.
KeyfileInvalidError rc: 40 traceback: no
Invalid key data for repository {} found in {}.
KeyfileMismatchError rc: 41 traceback: no
Mismatch between repository {} and key file {}.
KeyfileNotFoundError rc: 42 traceback: no
No key file for repository {} found in {}.
NotABorgKeyFile rc: 43 traceback: no
This file is not a borg key backup, aborting.
RepoKeyNotFoundError rc: 44 traceback: no
No key entry found in the config of repository {}.
RepoIdMismatch rc: 45 traceback: no
This key backup seems to be for a different backup repository, aborting.
UnencryptedRepo rc: 46 traceback: no
Key management not available for unencrypted repositories.
UnknownKeyType rc: 47 traceback: no
Key type {0} is unknown.
UnsupportedPayloadError rc: 48 traceback: no
Unsupported payload type {}. A newer version is required to access this repository.
UnsupportedKeyFormatError rc: 49 traceback:no
Your borg key is stored in an unsupported format. Try using a newer version of borg.
NoPassphraseFailure rc: 50 traceback: no
can not acquire a passphrase: {}
PasscommandFailure rc: 51 traceback: no
passcommand supplied in BORG_PASSCOMMAND failed: {}
PassphraseWrong rc: 52 traceback: no
passphrase supplied in BORG_PASSPHRASE, by BORG_PASSCOMMAND or via BORG_PASSPHRASE_FD is incorrect.
PasswordRetriesExceeded rc: 53 traceback: no
exceeded the maximum password retries
Cache.CacheInitAbortedError rc: 60 traceback: no
Cache.CacheInitAbortedError
Cache initialization aborted
Cache.EncryptionMethodMismatch rc: 61 traceback: no
Cache.EncryptionMethodMismatch
Repository encryption method changed since last access, refusing to continue
Cache.RepositoryAccessAborted rc: 62 traceback: no
Cache.RepositoryAccessAborted
Repository access aborted
Cache.RepositoryIDNotUnique rc: 63 traceback: no
Cache.RepositoryIDNotUnique
Cache is newer than repository - do you have multiple, independently updated repos with same ID?
Cache.RepositoryReplay rc: 64 traceback: no
Cache, or information obtained from the security directory is newer than repository - this is either an attack or unsafe (multiple repos with same ID)
LockError rc: 70 traceback: no
Cache.RepositoryReplay
Cache is newer than repository - this is either an attack or unsafe (multiple repos with same ID)
Buffer.MemoryLimitExceeded
Requested buffer size {} is above the limit of {}.
ExtensionModuleError
The Borg binary extension modules do not seem to be properly installed
IntegrityError
Data integrity error: {}
NoManifestError
Repository has no manifest.
PlaceholderError
Formatting Error: "{}".format({}): {}({})
KeyfileInvalidError
Invalid key file for repository {} found in {}.
KeyfileMismatchError
Mismatch between repository {} and key file {}.
KeyfileNotFoundError
No key file for repository {} found in {}.
PassphraseWrong
passphrase supplied in BORG_PASSPHRASE is incorrect
PasswordRetriesExceeded
exceeded the maximum password retries
RepoKeyNotFoundError
No key entry found in the config of repository {}.
UnsupportedManifestError
Unsupported manifest envelope. A newer version is required to access this repository.
UnsupportedPayloadError
Unsupported payload type {}. A newer version is required to access this repository.
NotABorgKeyFile
This file is not a borg key backup, aborting.
RepoIdMismatch
This key backup seems to be for a different backup repository, aborting.
UnencryptedRepo
Keymanagement not available for unencrypted repositories.
UnknownKeyType
Keytype {0} is unknown.
LockError
Failed to acquire the lock {}.
LockErrorT rc: 71 traceback: yes
LockErrorT
Failed to acquire the lock {}.
LockFailed rc: 72 traceback: yes
Failed to create/acquire the lock {} ({}).
LockTimeout rc: 73 traceback: no
Failed to create/acquire the lock {} (timeout).
NotLocked rc: 74 traceback: yes
Failed to release the lock {} (was not locked).
NotMyLock rc: 75 traceback: yes
Failed to release the lock {} (was/is locked, but not by me).
ConnectionClosed rc: 80 traceback: no
ConnectionClosed
Connection closed by remote host
ConnectionClosedWithHint rc: 81 traceback: no
Connection closed by remote host. {}
InvalidRPCMethod rc: 82 traceback: no
InvalidRPCMethod
RPC method {} is not valid
PathNotAllowed rc: 83 traceback: no
Repository path not allowed: {}
RemoteRepository.RPCServerOutdated rc: 84 traceback: no
PathNotAllowed
Repository path not allowed
RemoteRepository.RPCServerOutdated
Borg server is too old for {}. Required version {}
UnexpectedRPCDataFormatFromClient rc: 85 traceback: no
UnexpectedRPCDataFormatFromClient
Borg {}: Got unexpected RPC data format from client.
UnexpectedRPCDataFormatFromServer rc: 86 traceback: no
UnexpectedRPCDataFormatFromServer
Got unexpected RPC data format from server:
{}
ConnectionBrokenWithHint rc: 87 traceback: no
Connection to remote host is broken. {}
IntegrityError rc: 90 traceback: yes
Data integrity error: {}
FileIntegrityError rc: 91 traceback: yes
File failed integrity check: {}
DecompressionError rc: 92 traceback: yes
Decompression error: {}
Warnings
BorgWarning rc: 1
Warning: {}
BackupWarning rc: 1
{}: {}
FileChangedWarning rc: 100
{}: file changed while we backed it up
IncludePatternNeverMatchedWarning rc: 101
Include pattern '{}' never matched.
BackupError rc: 102
{}: backup error
BackupRaceConditionError rc: 103
{}: file type or inode changed while we backed it up (race condition, skipped file)
BackupOSError rc: 104
{}: {}
BackupPermissionError rc: 105
{}: {}
BackupIOError rc: 106
{}: {}
BackupFileNotFoundError rc: 107
{}: {}
Repository.AlreadyExists
Repository {} already exists.
Repository.CheckNeeded
Inconsistency detected. Please run "borg check {}".
Repository.DoesNotExist
Repository {} does not exist.
Repository.InsufficientFreeSpaceError
Insufficient free space to complete transaction (required: {}, available: {}).
Repository.InvalidRepository
{} is not a valid repository. Check repo config.
Repository.AtticRepository
Attic repository detected. Please run "borg upgrade {}".
Repository.ObjectNotFound
Object with key {} not found in repository {}.
Operations
- cache.begin_transaction
@ -766,4 +655,4 @@ Prompts
BORG_CHECK_I_KNOW_WHAT_I_AM_DOING
For "This is a potentially dangerous function..." (check --repair)
BORG_DELETE_I_KNOW_WHAT_I_AM_DOING
For "You requested to DELETE the repository completely *including* all archives it contains:"
For "You requested to completely DELETE the repository *including* all archives it contains:"

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

View file

@ -1,221 +0,0 @@
.. include:: ../global.rst.inc
.. highlight:: none
.. _packs:
Pack files
==========
Without pack files, each repository chunk is stored as a separate borgstore object.
For large repositories this means millions of individual objects, each requiring its
own I/O round trip to read or write. On high-latency backends (SFTP, cloud object
storage) this overhead dominates backup and restore times.
Pack files address this by grouping multiple chunks into a single store object. A
reader that needs one chunk does a partial read (range request) at a known offset
instead of fetching a separate file. Store object count drops from one-per-chunk to
one-per-pack.
.. _pack-format:
Pack File Format
----------------
There is no separate file header. Each blob starts with the 8-byte ``OBJ_MAGIC``
(``BORG_OBJ``), so a forward scanner can locate blob boundaries and identify
each chunk using only the pack file bytes with no external index.
Per-blob layout
~~~~~~~~~~~~~~~
Each blob is a self-contained unit::
Offset (relative to blob start) Size Type Field
-------------------------------- ---------------- ------- -----
0 len(OBJ_MAGIC) bytes OBJ_MAGIC = ASCII b"BORG_OBJ"
8 1 uint8 Format version: 0x01
9 32 bytes chunk_id
41 4 uint32le meta_size
45 4 uint32le data_size
49 meta_size bytes encrypted_meta
49 + meta_size data_size bytes encrypted_data
``chunk_id`` is the ID hash of the plaintext data (``id_hash(plaintext_data)``).
Storing it in the unencrypted header lets a scanner rebuild the
``chunk_id → location`` index without decrypting any blob.
``chunk_id`` is also written into ``encrypted_meta`` (the meta dict). The header
copy enables key-free scanning and recovery; the meta copy lets future code read
``chunk_id`` through the normal meta dict API without parsing the raw header layout.
The fixed part of each blob header is 49 bytes (``REPOOBJ_HEADER_SIZE``):
``len(OBJ_MAGIC)`` + 1 version + 32 chunk_id + 4 meta_size + 4 data_size.
``REPOOBJ_HEADER_SIZE = len(OBJ_MAGIC) + 1 + 32 + 4 + 4 = 49``
A reader locates the next blob by advancing::
next_blob_offset = current_blob_offset + REPOOBJ_HEADER_SIZE + meta_size + data_size
The per-blob magic limits the blast radius of corrupted length fields: if
``meta_size`` or ``data_size`` is damaged, the scanner loses at most one blob.
Once it finds the next ``OBJ_MAGIC`` sequence it resumes. Other corruption
(payload bit flips) is caught by AEAD on that blob without losing position.
Blobs follow one another contiguously with no padding::
OBJ_MAGIC | version=0x01 | chunk_id_0 | meta_size_0 | data_size_0 | encrypted_meta_0 | encrypted_data_0
OBJ_MAGIC | version=0x01 | chunk_id_1 | meta_size_1 | data_size_1 | encrypted_meta_1 | encrypted_data_1
...
Pack ID
~~~~~~~
The pack ID is the SHA-256 of the pack file's bytes::
pack_id = sha256(pack_bytes)
Content-addressing the file by its own bytes makes the name commit to the
content, so borgstore can verify and cache it and ``borg check`` can detect
silent corruption of the stored file.
Namespace
~~~~~~~~~
Pack files are stored under the ``packs/`` namespace in borgstore, using a
single directory level keyed on the first byte of the pack ID (hex-encoded)::
packs/
00/ .. ff/
<pack_id_hex>
.. _pack-index-entry:
Pack Index Entry
----------------
Each pack contains one blob. The pack for a given chunk is always at::
packs/<hex(pack_id)>
A ChunkIndex entry maps a chunk to its pack::
chunk_id → pack_id
Since each pack holds exactly one blob, the blob is always at offset 0 and
its length is the full file size. No offset or length field is stored in the
index for this phase.
.. _pack-write-order:
Write Order and Crash Safety
-----------------------------
Pack data must be stored before any archive pointer references it.
The required write order is:
1. Store the pack file to ``packs/<pack_id>`` via borgstore.
2. Store the partial index file to ``index/<index_id>`` (see :ref:`pack-index-namespace`).
3. Write the archive and archive pointer. This is the sole commit point.
A crash between steps 1 and 2 leaves orphan pack files in ``packs/``. No archive
references these chunks; ``borg compact`` removes them on the next run.
A crash between steps 2 and 3 leaves a partial index file covering packs not yet
committed to any archive. The extra index entries point to valid, fully-written pack
data; they are harmless and will be cleaned up by the next ``borg compact``.
A crash after step 3 cannot leave the repository in an inconsistent state. The
archive pointer write is the commit point: data not referenced by any archive pointer
is unreachable and treated as garbage by ``borg compact``.
Only ``borg compact`` and ``borg check --repair`` delete pack files. When compact
determines via mark-and-sweep that none of a pack's blobs are referenced by any
archive, it removes the whole file. Individual blobs cannot be removed without
rewriting the entire pack, so deletion always operates at pack granularity.
.. _pack-index-namespace:
Index Namespace
---------------
Chunk-to-location mappings are stored as a separate set of encrypted partial index
files under the ``index/`` namespace.
Each partial index file covers the packs written in one backup session. Its name is
the SHA-256 digest of its own content. A first backup of a large dataset may produce
a large partial index file; using the same medium-sized file writer as compact for
``borg create`` would bound that. That is the intended direction.
::
index/
<sha256_of_content_hex>
Content-addressed naming makes each partial index file self-verifying and idempotent:
writing the same index data twice produces the same filename, so a repeated write is
a no-op.
Partial index files are write-once. A session stores new partial index files via
borgstore; existing files are never modified. On repository open all files under
``index/`` are loaded via borgstore, decrypted, and merged into the in-memory ChunkIndex
(a ``borghash`` ``HashTableNT`` keyed on ``chunk_id``). The merge is commutative and
idempotent; order does not matter.
``borg compact`` rewrites the ``index/`` namespace: it identifies live chunks via
mark-and-sweep, consolidates the surviving mappings into medium-sized replacement
files (targeting roughly 10100 packs per file), and removes the files it supersedes.
Medium-sized files keep the open-time merge cost bounded while avoiding the
cache-invalidation traffic on other clients that a single all-in-one index would
cause.
If the entire ``index/`` namespace is lost or corrupt, the ChunkIndex can be rebuilt
by scanning pack files directly; see :ref:`pack-recovery`.
.. _pack-recovery:
Recovery Path
-------------
When ``borg check --repair`` detects a missing or incomplete ChunkIndex it rebuilds
it by forward-scanning all pack files in ``packs/``.
Each blob's unencrypted header supplies the ``OBJ_MAGIC`` (for re-sync after
corruption), the ``chunk_id``, and the size fields needed to locate the next blob.
The scan produces a complete ``chunk_id → (pack_id, offset, length)`` mapping
without decrypting any blob and without the repository key.
.. _pack-repo-version:
Repository Version and Feature Flags
--------------------------------------
Repositories using pack files require repository version **4**. Clients that only
accept version 3 refuse to open a version 4 repository with an unsupported-version
error before any data is read.
In addition, the repository ``config.feature_flags`` must include ``pack_files`` in
the mandatory set for all access modes:
.. code-block:: python
config = {
"feature_flags": {
"read": {"mandatory": ["pack_files"]},
"write": {"mandatory": ["pack_files"]},
"check": {"mandatory": ["pack_files"]},
}
}
A client that does not recognise the ``pack_files`` feature flag will refuse to open
the repository with a ``MandatoryFeatureUnsupported`` error regardless of the version
number. The two guards cover different failure modes: the version bump stops clients
that predate feature-flag support entirely; the feature flag gives a clearer error
message to clients that understand feature flags but don't know about packs yet.
There is no migration path from version 3 repositories to version 4. Users of the
version 3 beta format must create a new repository with ``borg repo-create``.

View file

@ -1,5 +1,3 @@
.. include:: ../global.rst.inc
.. somewhat surprisingly the "bash" highlighter gives nice results with
the pseudo-code notation used in the "Encryption" section.
@ -24,22 +22,25 @@ The attack model of Borg is that the environment of the client process
attacker has any and all access to the repository, including interactive
manipulation (man-in-the-middle) for remote repositories.
Furthermore, the client environment is assumed to be persistent across
Furthermore the client environment is assumed to be persistent across
attacks (practically this means that the security database cannot be
deleted between attacks).
Under these circumstances Borg guarantees that the attacker cannot
1. modify the data of any archive without the client detecting the change
2. rename or add an archive without the client detecting the change
2. rename, remove or add an archive without the client detecting the change
3. recover plain-text data
4. recover definite (heuristics based on access patterns are possible)
structural information such as the object graph (which archives
refer to what chunks)
The attacker can always impose a denial of service by definition (they could
block connections to the repository, or delete it partly or entirely).
The attacker can always impose a denial of service per definition (he could
forbid connections to the repository, or delete it entirely).
When the above attack model is extended to include multiple clients
independently updating the same repository, then Borg fails to provide
confidentiality (i.e. guarantees 3) and 4) do not apply any more).
.. _security_structural_auth:
@ -47,12 +48,12 @@ Structural Authentication
-------------------------
Borg is fundamentally based on an object graph structure (see :ref:`internals`),
where the root objects are the archives.
where the root object is called the manifest.
Borg follows the `Horton principle`_, which states that
not only the message must be authenticated, but also its meaning (often
expressed through context), because every object used is referenced by a
parent object through its object ID up to the archive list entry. The object ID in
parent object through its object ID up to the manifest. The object ID in
Borg is a MAC of the object's plaintext, therefore this ensures that
an attacker cannot change the context of an object without forging the MAC.
@ -60,45 +61,50 @@ In other words, the object ID itself only authenticates the plaintext of the
object and not its context or meaning. The latter is established by a different
object referring to an object ID, thereby assigning a particular meaning to
an object. For example, an archive item contains a list of object IDs that
represent packed file metadata. On their own, it's not clear that these objects
represent packed file metadata. On their own it's not clear that these objects
would represent what they do, but by the archive item referring to them
in a particular part of its own data structure assigns this meaning.
This results in a directed acyclic graph of authentication from the archive
list entry to the data chunks of individual files.
This results in a directed acyclic graph of authentication from the manifest
to the data chunks of individual files.
Above used to be all for borg 1.x and was the reason why it needed the
tertiary authentication mechanism (TAM) for manifest and archives.
.. _tam_description:
borg 2 now stores the ro_type ("meaning") of a repo object's data into that
object's metadata (like e.g.: manifest vs. archive vs. user file content data).
When loading data from the repo, borg verifies that the type of object it got
matches the type it wanted. borg 2 does not use TAMs any more.
.. rubric:: Authenticating the manifest
As both the object's metadata and data are AEAD encrypted and also bound to
the object ID (via giving the ID as AAD), there is no way an attacker (without
access to the borg key) could change the type of the object or move content
to a different object ID.
Since the manifest has a fixed ID (000...000) the aforementioned authentication
does not apply to it, indeed, cannot apply to it; it is impossible to authenticate
the root node of a DAG through its edges, since the root node has no incoming edges.
This effectively 'anchors' each archive to the key, which is controlled by the
client, thereby anchoring the DAG starting from the archives list entry,
making it impossible for an attacker to add or modify any part of the
DAG without Borg being able to detect the tampering.
With the scheme as described so far an attacker could easily replace the manifest,
therefore Borg includes a tertiary authentication mechanism (TAM) that is applied
to the manifest since version 1.0.9 (see :ref:`tam_vuln`).
Please note that removing an archive by removing an entry from archives/*
is possible and is done by ``borg delete`` and ``borg prune`` within their
normal operation. An attacker could also remove some entries there, but, due to
encryption, would not know what exactly they are removing. An attacker with
repository access could also remove other parts of the repository or the whole
repository, so there is not much point in protecting against archive removal.
TAM works by deriving a separate key through HKDF_ from the other encryption and
authentication keys and calculating the HMAC of the metadata to authenticate [#]_::
The borg 1.x way of having the archives list within the manifest chunk was
problematic as it required a read-modify-write operation on the manifest,
requiring a lock on the repository. We want to try less locking and more
parallelism in future.
# RANDOM(n) returns n random bytes
salt = RANDOM(64)
Passphrase notes
----------------
ikm = id_key || enc_key || enc_hmac_key
# *context* depends on the operation, for manifest authentication it is
# the ASCII string "borg-metadata-authentication-manifest".
tam_key = HKDF-SHA-512(ikm, salt, context)
# *data* is a dict-like structure
data[hmac] = zeroes
packed = pack(data)
data[hmac] = HMAC(tam_key, packed)
packed_authenticated = pack(data)
Since an attacker cannot gain access to this key and also cannot make the
client authenticate arbitrary data using this mechanism, the attacker is unable
to forge the authentication.
This effectively 'anchors' the manifest to the key, which is controlled by the
client, thereby anchoring the entire DAG, making it impossible for an attacker
to add, remove or modify any part of the DAG without Borg being able to detect
the tampering.
Note that when using BORG_PASSPHRASE the attacker cannot swap the *entire*
repository against a new repository with e.g. repokey mode and no passphrase,
@ -108,95 +114,109 @@ However, interactively a user might not notice this kind of attack
immediately, if she assumes that the reason for the absent passphrase
prompt is a set BORG_PASSPHRASE. See issue :issue:`2169` for details.
.. [#] The reason why the authentication tag is stored in the packed
data itself is that older Borg versions can still read the
manifest this way, while a changed layout would have broken
compatibility.
.. _security_encryption:
Encryption
----------
AEAD modes
~~~~~~~~~~
Encryption is currently based on the Encrypt-then-MAC construction,
which is generally seen as the most robust way to create an authenticated
encryption scheme from encryption and message authentication primitives.
Modes: --encryption (repokey|keyfile)-[blake2-](aes-ocb|chacha20-poly1305)
Every operation (encryption, MAC / authentication, chunk ID derivation)
uses independent, random keys generated by `os.urandom`_ [#]_.
Supported: borg 2.0+
Borg does not support unauthenticated encryption -- only authenticated encryption
schemes are supported. No unauthenticated encryption schemes will be added
in the future.
Encryption with these modes is based on AEAD ciphers (authenticated encryption
with associated data) and session keys.
Depending on the chosen mode (see :ref:`borg_init`) different primitives are used:
Depending on the chosen mode (see :ref:`borg_repo-create`) different AEAD ciphers are used:
- The actual encryption is currently always AES-256 in CTR mode. The
counter is added in plaintext, since it is needed for decryption,
and is also tracked locally on the client to avoid counter reuse.
- AES-256-OCB - super fast, single-pass algorithm IF you have hw accelerated AES.
- chacha20-poly1305 - very fast, purely software based AEAD cipher.
- The authentication primitive is either HMAC-SHA-256 or BLAKE2b-256
in a keyed mode.
The chunk ID is derived via a MAC over the plaintext (mac key taken from borg key):
Both HMAC-SHA-256 and BLAKE2b have undergone extensive cryptanalysis
and have proven secure against known attacks. The known vulnerability
of SHA-256 against length extension attacks does not apply to HMAC-SHA-256.
The authentication primitive should be chosen based upon SHA hardware support:
all AMD Ryzen, Intel 10th+ generation mobile and Intel 11th+ generation
desktop processors, Apple M1+ and most current ARM64 architectures support
SHA extensions and are likely to perform best with HMAC-SHA-256.
64-bit CPUs without SHA extensions are likely to perform best with BLAKE2b.
- HMAC-SHA256 - super fast IF you have hw accelerated SHA256 (see section "Encryption" below).
- Blake2b - very fast, purely software based algorithm.
For each borg invocation, a new session id is generated by `os.urandom`_.
From that session id, the initial key material (ikm, taken from the borg key)
and an application and cipher specific salt, borg derives a session key using a
"one-step KDF" based on just sha256.
For each session key, IVs (nonces) are generated by a counter which increments for
each encrypted message.
Session::
sessionid = os.urandom(24)
domain = "borg-session-key-CIPHERNAME"
sessionkey = sha256(crypt_key + sessionid + domain)
message_iv = 0
- The primitive used for authentication is always the same primitive
that is used for deriving the chunk ID, but they are always
used with independent keys.
Encryption::
id = MAC(id_key, data)
id = AUTHENTICATOR(id_key, data)
compressed = compress(data)
header = type-byte || 00h || message_iv || sessionid
aad = id || header
message_iv++
encrypted, auth_tag = AEAD_encrypt(session_key, message_iv, compressed, aad)
authenticated = header || auth_tag || encrypted
iv = reserve_iv()
encrypted = AES-256-CTR(enc_key, 8-null-bytes || iv, compressed)
authenticated = type-byte || AUTHENTICATOR(enc_hmac_key, encrypted) || iv || encrypted
Decryption::
# Given: input *authenticated* data and a *chunk-id* to assert
type-byte, past_message_iv, past_sessionid, auth_tag, encrypted = SPLIT(authenticated)
# Given: input *authenticated* data, possibly a *chunk-id* to assert
type-byte, mac, iv, encrypted = SPLIT(authenticated)
ASSERT(type-byte is correct)
ASSERT( CONSTANT-TIME-COMPARISON( mac, AUTHENTICATOR(enc_hmac_key, encrypted) ) )
domain = "borg-session-key-CIPHERNAME"
past_key = sha256(crypt_key + past_sessionid + domain)
decrypted = AEAD_decrypt(past_key, past_message_iv, authenticated)
decrypted = AES-256-CTR(enc_key, 8-null-bytes || iv, encrypted)
decompressed = decompress(decrypted)
Notable:
ASSERT( CONSTANT-TIME-COMPARISON( chunk-id, AUTHENTICATOR(id_key, decompressed) ) )
- More modern and often faster AEAD ciphers instead of self-assembled stuff.
- Due to the usage of session keys, IVs (nonces) do not need special care here as
they did for the legacy encryption modes.
- The id is now also input into the authentication tag computation.
This strongly associates the id with the written data (== associates the key with
the value). When later reading the data for some id, authentication will only
succeed if what we get was really written by us for that id.
The client needs to track which counter values have been used, since
encrypting a chunk requires a starting counter value and no two chunks
may have overlapping counter ranges (otherwise the bitwise XOR of the
overlapping plaintexts is revealed).
The client does not directly track the counter value, because it
changes often (with each encrypted chunk), instead it commits a
"reservation" to the security database and the repository by taking
the current counter value and adding 4 GiB / 16 bytes (the block size)
to the counter. Thus the client only needs to commit a new reservation
every few gigabytes of encrypted data.
Legacy modes
~~~~~~~~~~~~
This mechanism also avoids reusing counter values in case the client
crashes or the connection to the repository is severed, since any
reservation would have been committed to both the security database
and the repository before any data is encrypted. Borg uses its
standard mechanism (SaveFile) to ensure that reservations are durable
(on most hardware / storage systems), therefore a crash of the
client's host would not impact tracking of reservations.
Modes: --encryption (repokey|keyfile)-[blake2]
However, this design is not infallible, and requires synchronization
between clients, which is handled through the repository. Therefore in
a multiple-client scenario a repository can trick a client into
reusing counter values by ignoring counter reservations and replaying
the manifest (which will fail if the client has seen a more recent
manifest or has a more recent nonce reservation). If the repository is
untrusted, but a trusted synchronization channel exists between
clients, the security database could be synchronized between them over
said trusted channel. This is not part of Borg's functionality.
Supported: borg < 2.0
These were the AES-CTR based modes in previous borg versions.
borg 2.0 does not support creating new repos using these modes,
but ``borg transfer`` can still read such existing repos.
.. [#] Using the :ref:`borg key migrate-to-repokey <borg_key_migrate-to-repokey>`
command a user can convert repositories created using Attic in "passphrase"
mode to "repokey" mode. In this case the keys were directly derived from
the user's passphrase at some point using PBKDF2.
Borg does not support "passphrase" mode otherwise any more.
.. _key_encryption:
@ -210,23 +230,32 @@ For offline storage of the encryption keys they are encrypted with a
user-chosen passphrase.
A 256 bit key encryption key (KEK) is derived from the passphrase
using argon2_ with a random 256 bit salt. The KEK is then used
to Encrypt-*then*-MAC a packed representation of the keys using the
chacha20-poly1305 AEAD cipher and a constant IV == 0.
The ciphertext is then converted to base64.
using PBKDF2-HMAC-SHA256 with a random 256 bit salt which is then used
to Encrypt-*and*-MAC (unlike the Encrypt-*then*-MAC approach used
otherwise) a packed representation of the keys with AES-256-CTR with a
constant initialization vector of 0. A HMAC-SHA256 of the plaintext is
generated using the same KEK and is stored alongside the ciphertext,
which is converted to base64 in its entirety.
This base64 blob (commonly referred to as *keyblob*) is then stored in
the key file or in the repository config (keyfile and repokey modes
respectively).
The use of a constant IV is secure because an identical passphrase will
result in a different derived KEK for every key encryption due to the salt.
This scheme, and specifically the use of a constant IV with the CTR
mode, is secure because an identical passphrase will result in a
different derived KEK for every key encryption due to the salt.
The use of Encrypt-and-MAC instead of Encrypt-then-MAC is seen as
uncritical (but not ideal) here, since it is combined with AES-CTR mode,
which is not vulnerable to padding attacks.
.. seealso::
Refer to the :ref:`key_files` section for details on the format.
Refer to issue :issue:`747` for suggested improvements of the encryption
scheme and password-based key derivation.
Implementations used
--------------------
@ -234,16 +263,29 @@ Implementations used
We do not implement cryptographic primitives ourselves, but rely
on widely used libraries providing them:
- AES-OCB and CHACHA20-POLY1305 from OpenSSL 1.1 are used,
- AES-CTR and HMAC-SHA-256 from OpenSSL 1.0 / 1.1 are used,
which is also linked into the static binaries we provide.
We think this is not an additional risk, since we don't ever
use OpenSSL's networking, TLS or X.509 code, but only their
primitives implemented in libcrypto.
- SHA-256, SHA-512 and BLAKE2b from Python's hashlib_ standard library module are used.
- HMAC and a constant-time comparison from Python's hmac_ standard library module are used.
- argon2 is used via argon2-cffi.
Borg requires a Python built with OpenSSL support (due to PBKDF2), therefore
these functions are delegated to OpenSSL by Python.
- HMAC, PBKDF2 and a constant-time comparison from Python's hmac_ standard
library module is used. While the HMAC implementation is written in Python,
the PBKDF2 implementation is provided by OpenSSL. The constant-time comparison
(``compare_digest``) is written in C and part of Python.
Implemented cryptographic constructions are:
- Encrypt-then-MAC based on AES-256-CTR and either HMAC-SHA-256
or keyed BLAKE2b256 as described above under Encryption_.
- Encrypt-and-MAC based on AES-256-CTR and HMAC-SHA-256
as described above under `Offline key security`_.
- HKDF_-SHA-512
.. _Horton principle: https://en.wikipedia.org/wiki/Horton_Principle
.. _HKDF: https://tools.ietf.org/html/rfc5869
.. _length extension: https://en.wikipedia.org/wiki/Length_extension_attack
.. _hashlib: https://docs.python.org/3/library/hashlib.html
.. _hmac: https://docs.python.org/3/library/hmac.html
@ -264,7 +306,7 @@ SSH server -- Borg RPC does not contain *any* networking
code. Networking is done by the SSH client running in a separate
process, Borg only communicates over the standard pipes (stdout,
stderr and stdin) with this process. This also means that Borg doesn't
have to use a SSH client directly (or SSH at all). For example,
have to directly use a SSH client (or SSH at all). For example,
``sudo`` or ``qrexec`` could be used as an intermediary.
By using the system's SSH client and not implementing a
@ -341,12 +383,13 @@ Compression and Encryption
Combining encryption with compression can be insecure in some contexts (e.g. online protocols).
There was some discussion about this in :issue:`1040` and for Borg some developers
There was some discussion about this in `github issue #1040`_ and for Borg some developers
concluded this is no problem at all, some concluded this is hard and extremely slow to exploit
and thus no problem in practice.
No matter what, there is always the option not to use compression if you are worried about this.
.. _github issue #1040: https://github.com/borgbackup/borg/issues/1040
Fingerprinting
==============
@ -361,25 +404,19 @@ The chunks stored in the repo are the (compressed, encrypted and authenticated)
output of the chunker. The sizes of these stored chunks are influenced by the
compression, encryption and authentication.
buzhash and buzhash64 chunker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
buzhash chunker
+++++++++++++++
The buzhash chunkers chunk according to the input data, the chunker's
parameters and secret key material (which all influence the chunk boundary
The buzhash chunker chunks according to the input data, the chunker's
parameters and the secret chunker seed (which all influence the chunk boundary
positions).
Secret key material:
- "buzhash": chunker seed (32bits), used for XORing the hardcoded buzhash table
- "buzhash64": bh64_key (256bits) is derived from ID key, used to cryptographically
generate the table.
Small files below some specific threshold (default: 512 KiB) result in only one
chunk (identical content / size as the original file), bigger files result in
multiple chunks.
fixed chunker
~~~~~~~~~~~~~
+++++++++++++
This chunker yields fixed sized chunks, with optional support of a differently
sized header chunk. The last chunk is not required to have the full block size
@ -411,24 +448,6 @@ To summarize, this is making size-based fingerprinting difficult:
- optional ``obfuscate`` pseudo compressor with different choices
of algorithm and parameters
Secret key usage against fingerprinting
---------------------------------------
Borg uses the borg key also for chunking and chunk ID generation to protect against fingerprinting.
As usual for borg's attack model, the attacker is assumed to have access to a borg repository.
The borg key includes a secret random chunk_seed which (together with the chunking algorithm)
determines the cutting places and thereby the length of the chunks cut. Because the attacker trying
a chunk length fingerprinting attack would use a different chunker secret than the borg setup being
attacked, they would not be able to determine the set of chunk lengths for a known set of files.
The borg key also includes a secret random id_key. The chunk ID generation is not just using a simple
cryptographic hash like sha256 (because that would be insecure as an attacker could see the hashes of
small files that result only in 1 chunk in the repository). Instead, borg uses keyed hash (a MAC,
e.g. HMAC-SHA256) to compute the chunk ID from the content and the secret id_key. Thus, an attacker
can't compute the same chunk IDs for a known set of small files to determine whether these are stored
in the attacked repository.
Stored chunk proximity
----------------------

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

View file

@ -1,8 +1,8 @@
Introduction
============
.. This shim is here to fix the structure in the PDF
rendering. Without this stub, the elements in the toctree of
index.rst show up a level below the README file included.
.. this shim is here to fix the structure in the PDF
rendering. without this stub, the elements in the toctree of
index.rst show up a level below the README file included
.. include:: ../README.rst

View file

@ -1,91 +0,0 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-analyze" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-analyze \- Analyzes archives.
.SH SYNOPSIS
.sp
borg [common options] analyze [options]
.SH DESCRIPTION
.sp
Analyze archives to find \(dqhot spots\(dq.
.sp
\fBborg analyze\fP relies on the usual archive matching options to select the
archives that should be considered for analysis (e.g. \fB\-a series_name\fP).
Then it iterates over all matching archives, over all contained files, and
collects information about chunks stored in all directories it encounters.
.sp
It considers chunk IDs and their plaintext sizes (we do not have the compressed
size in the repository easily available) and adds up the sizes of added and removed
chunks per direct parent directory, and outputs a list of \(dqdirectory: size\(dq.
.sp
You can use that list to find directories with a lot of \(dqactivity\(dq — maybe
some of these are temporary or cache directories you forgot to exclude.
.sp
To avoid including these unwanted directories in your backups, you can carefully
exclude them in \fBborg create\fP (for future backups) or use \fBborg recreate\fP
to recreate existing archives without them.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS Archive filters
.INDENT 0.0
.TP
.BI \-a \ PATTERN\fR,\fB \ \-\-match\-archives \ PATTERN
only consider archives matching all patterns. See \(dqborg help match\-archives\(dq.
.TP
.BI \-\-sort\-by \ KEYS
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id, tags, host, user; default is: timestamp
.TP
.BI \-\-first \ N
consider the first N archives after other filters are applied
.TP
.BI \-\-last \ N
consider the last N archives after other filters are applied
.TP
.BI \-\-oldest \ TIMESPAN
consider archives between the oldest archive\(aqs timestamp and (oldest + TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newest \ TIMESPAN
consider archives between the newest archive\(aqs timestamp and (newest \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-older \ TIMESPAN
consider archives older than (now \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newer \ TIMESPAN
consider archives newer than (now \- TIMESPAN), e.g., 7d or 12m.
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
The Borg Collective
.\" End of generated man page.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,29 +27,31 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-benchmark-crud" "1" "2026-06-16" "" "borg backup tool"
.SH Name
.TH "BORG-BENCHMARK-CRUD" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-benchmark-crud \- Benchmark Create, Read, Update, Delete for archives.
.SH SYNOPSIS
.sp
borg [common options] benchmark crud [options] PATH
borg [common options] benchmark crud [options] REPOSITORY PATH
.SH DESCRIPTION
.sp
This command benchmarks borg CRUD (create, read, update, delete) operations.
.sp
It creates input data below the given PATH and backs up this data into the given REPO.
It creates input data below the given PATH and backups this data into the given REPO.
The REPO must already exist (it could be a fresh empty repo or an existing repo, the
command will create / read / update / delete some archives named borg\-benchmark\-crud* there.
.sp
Make sure you have free space there; you will need about 1 GB each (+ overhead).
Make sure you have free space there, you\(aqll need about 1GB each (+ overhead).
.sp
If your repository is encrypted and borg needs a passphrase to unlock the key, use:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.nf
.ft C
BORG_PASSPHRASE=mysecret borg benchmark crud REPO PATH
.EE
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
@ -87,18 +88,16 @@ See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B PATH
path where to create benchmark input data
.UNINDENT
.SS options
.INDENT 0.0
.B REPOSITORY
repository to use for benchmark (must exist)
.TP
.B \-\-json\-lines
Format output as JSON Lines.
.B PATH
path were to create benchmark input data
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,13 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-benchmark" "1" "2026-06-16" "" "borg backup tool"
.SH Name
.TH "BORG-BENCHMARK" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-benchmark \- benchmark command
.SH SYNOPSIS
.nf
borg [common options] benchmark crud ...
borg [common options] benchmark cpu ...
.fi
.sp
.SH DESCRIPTION
@ -42,7 +40,8 @@ borg [common options] benchmark cpu ...
These commands do various benchmarks.
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-benchmark\-crud(1)\fP, \fIborg\-benchmark\-cpu(1)\fP
.SH Author
\fIborg\-common(1)\fP, \fIborg\-benchmark\-crud(1)\fP
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,23 +27,30 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-break-lock" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-break-lock \- Breaks the repository lock (for example, if it was left by a dead Borg process).
.TH "BORG-BREAK-LOCK" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-break-lock \- Break the repository lock (e.g. in case it was left by a dead borg.
.SH SYNOPSIS
.sp
borg [common options] break\-lock [options]
borg [common options] break\-lock [options] [REPOSITORY]
.SH DESCRIPTION
.sp
This command breaks the repository and cache locks.
Use with care and only when no Borg process (on any machine) is
trying to access the cache or the repository.
Please use carefully and only while no borg process (on any machine) is
trying to access the Cache or the Repository.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B REPOSITORY
repository for which to break the locks
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,8 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.TH BORG-CHANGE-PASSPHRASE 1 "2017-11-25" "" "borg backup tool"
.SH NAME
borg-change-passphrase \- Change repository key file passphrase
.
.nr rst2man-indent-level 0
.
@ -28,36 +30,28 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-benchmark-cpu" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-benchmark-cpu \- Benchmark CPU-bound operations.
.SH SYNOPSIS
.sp
borg [common options] benchmark cpu [options]
borg [common options] change\-passphrase [options] [REPOSITORY]
.SH DESCRIPTION
.sp
This command benchmarks miscellaneous CPU\-bound Borg operations.
The key files used for repository encryption are optionally passphrase
protected. This command can be used to change this passphrase.
.sp
It creates input data in memory, runs the operation and then displays throughput.
To reduce outside influence on the timings, please make sure to run this with:
.INDENT 0.0
.IP \(bu 2
an otherwise as idle as possible machine
.IP \(bu 2
enough free memory so there will be no slow down due to paging activity
.UNINDENT
Please note that this command only changes the passphrase, but not any
secret protected by it (like e.g. encryption/MAC keys or chunker seed).
Thus, changing the passphrase after passphrase and borg key got compromised
does not protect future (nor past) backups to the same repository.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS options
.INDENT 0.0
.TP
.B \-\-json
format output as JSON
.UNINDENT
.SS arguments
.sp
REPOSITORY
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,12 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-check" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-check \- Checks repository consistency.
.TH "BORG-CHECK" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-check \- Check repository consistency
.SH SYNOPSIS
.sp
borg [common options] check [options]
borg [common options] check [options] [REPOSITORY_OR_ARCHIVE]
.SH DESCRIPTION
.sp
The check command verifies the consistency of a repository and its archives.
@ -41,25 +40,23 @@ It consists of two major steps:
.INDENT 0.0
.IP 1. 3
Checking the consistency of the repository itself. This includes checking
the file magic headers, and both the metadata and data of all objects in
the repository. The read data is checked by size and hash. Bit rot and other
the segment magic headers, and both the metadata and data of all objects in
the segments. The read data is checked by size and CRC. Bit rot and other
types of accidental damage can be detected this way. Running the repository
check can be split into multiple partial checks using \fB\-\-max\-duration\fP\&.
When checking an \%<ssh://> remote repository, please note that the checks run on
the server and do not cause significant network traffic.
When checking a remote repository, please note that the checks run on the
server and do not cause significant network traffic.
.IP 2. 3
Checking consistency and correctness of the archive metadata and optionally
archive data (requires \fB\-\-verify\-data\fP). This includes ensuring that the
repository manifest exists, the archive metadata chunk is present, and that
all chunks referencing files (items) in the archive exist. This requires
reading archive and file metadata, but not data. To scan for archives whose
entries were lost from the archive directory, pass \fB\-\-find\-lost\-archives\fP\&.
It requires reading all data and is hence very time\-consuming.
To additionally cryptographically verify the file (content) data integrity,
pass \fB\-\-verify\-data\fP, which is even more time\-consuming.
.sp
When checking archives of a remote repository, archive checks run on the client
machine because they require decrypting data and therefore the encryption key.
reading archive and file metadata, but not data. To cryptographically verify
the file (content) data integrity pass \fB\-\-verify\-data\fP, but keep in mind
that this requires reading all data and is hence very time consuming. When
checking archives of a remote repository, archive checks run on the client
machine because they require decrypting data and therefore the encryption
key.
.UNINDENT
.sp
Both steps can also be run independently. Pass \fB\-\-repository\-only\fP to run the
@ -67,7 +64,7 @@ repository checks only, or pass \fB\-\-archives\-only\fP to run the archive chec
only.
.sp
The \fB\-\-max\-duration\fP option can be used to split a long\-running repository
check into multiple partial checks. After the given number of seconds, the check
check into multiple partial checks. After the given number of seconds the check
is interrupted. The next partial check will continue where the previous one
stopped, until the full repository has been checked. Assuming a complete check
would take 7 hours, then running a daily check with \fB\-\-max\-duration=3600\fP
@ -78,34 +75,27 @@ archive checks, nor enable repair mode. Consequently, if you want to use
\fB\-\-max\-duration\fP you must also pass \fB\-\-repository\-only\fP, and must not pass
\fB\-\-archives\-only\fP, nor \fB\-\-repair\fP\&.
.sp
\fBWarning:\fP Please note that partial repository checks (i.e., running with
\fBWarning:\fP Please note that partial repository checks (i.e. running it with
\fB\-\-max\-duration\fP) can only perform non\-cryptographic checksum checks on the
repository files. Enabling partial repository checks excludes archive checks
for the same reason. Therefore, partial checks may be useful only with very large
repositories where a full check would take too long.
segment files. A full repository check (i.e. without \fB\-\-max\-duration\fP) can
also do a repository index check. Enabling partial repository checks excepts
archive checks for the same reason. Therefore partial checks may be useful with
very large repositories only where a full check would take too long.
.sp
The \fB\-\-verify\-data\fP option will perform a full integrity verification of data,
which means reading the data from the repository, decrypting and decompressing it.
It is a complete cryptographic verification and hence very time\-consuming, but
will detect any accidental and malicious corruption. Tamper\-resistance is only
guaranteed for encrypted repositories against attackers without access to the keys.
You cannot use \fB\-\-verify\-data\fP with \fB\-\-repository\-only\fP\&.
.sp
The \fB\-\-find\-lost\-archives\fP option will also scan the whole repository, but
tells Borg to search for lost archive metadata. If Borg encounters any archive
metadata that does not match an archive directory entry (including
soft\-deleted archives), it means that an entry was lost.
Unless \fBborg compact\fP is called, these archives can be fully restored with
\fB\-\-repair\fP\&. Please note that \fB\-\-find\-lost\-archives\fP must read a lot of
data from the repository and is thus very time\-consuming. You cannot use
\fB\-\-find\-lost\-archives\fP with \fB\-\-repository\-only\fP\&.
The \fB\-\-verify\-data\fP option will perform a full integrity verification (as
opposed to checking the CRC32 of the segment) of data, which means reading the
data from the repository, decrypting and decompressing it. It is a complete
cryptographic verification and hence very time consuming, but will detect any
accidental and malicious corruption. Tamper\-resistance is only guaranteed for
encrypted repositories against attackers without access to the keys. You can
not use \fB\-\-verify\-data\fP with \fB\-\-repository\-only\fP\&.
.SS About repair mode
.sp
The check command is a read\-only task by default. If any corruption is found,
The check command is a readonly task by default. If any corruption is found,
Borg will report the issue and proceed with checking. To actually repair the
issues found, pass \fB\-\-repair\fP\&.
.sp
\fBNote:\fP
\fBNOTE:\fP
.INDENT 0.0
.INDENT 3.5
\fB\-\-repair\fP is a \fBPOTENTIALLY DANGEROUS FEATURE\fP and might lead to data
@ -124,7 +114,7 @@ It is highly recommended to create a backup of your repository before running
in repair mode (i.e. running it with \fB\-\-repair\fP).
.sp
Repair mode will attempt to fix any corruptions found. Fixing corruptions does
not mean recovering lost data: Borg cannot magically restore data lost due to
not mean recovering lost data: Borg can not magically restore data lost due to
e.g. a hardware failure. Repairing a repository means sacrificing some data
for the sake of the repository as a whole and the remaining data. Hence it is,
by definition, a potentially lossy task.
@ -132,20 +122,45 @@ by definition, a potentially lossy task.
In practice, repair mode hooks into both the repository and archive checks:
.INDENT 0.0
.IP 1. 3
When checking the repository\(aqs consistency, repair mode removes corrupted
objects from the repository after it did a 2nd try to read them correctly.
When checking the repository\(aqs consistency, repair mode will try to recover
as many objects from segments with integrity errors as possible, and ensure
that the index is consistent with the data stored in the segments.
.IP 2. 3
When checking the consistency and correctness of archives, repair mode might
remove whole archives from the manifest if their archive metadata chunk is
corrupt or lost. Borg will also report files that reference missing chunks.
corrupt or lost. On a chunk level (i.e. the contents of files), repair mode
will replace corrupt or lost chunks with a same\-size replacement chunk of
zeroes. If a previously zeroed chunk reappears, repair mode will restore
this lost chunk using the new chunk. Lastly, repair mode will also delete
orphaned chunks (e.g. caused by read errors while creating the archive).
.UNINDENT
.sp
If \fB\-\-repair \-\-find\-lost\-archives\fP is given, previously lost entries will
be recreated in the archive directory. This is only possible before
\fBborg compact\fP would remove the archives\(aq data completely.
Most steps taken by repair mode have a one\-time effect on the repository, like
removing a lost archive from the repository. However, replacing a corrupt or
lost chunk with an all\-zero replacement will have an ongoing effect on the
repository: When attempting to extract a file referencing an all\-zero chunk,
the \fBextract\fP command will distinctly warn about it. The FUSE filesystem
created by the \fBmount\fP command will reject reading such a \(dqzero\-patched\(dq
file unless a special mount option is given.
.sp
As mentioned earlier, Borg might be able to \(dqheal\(dq a \(dqzero\-patched\(dq file in
repair mode, if all its previously lost chunks reappear (e.g. via a later
backup). This is achieved by Borg not only keeping track of the all\-zero
replacement chunks, but also by keeping metadata about the lost chunks. In
repair mode Borg will check whether a previously lost chunk reappeared and will
replace the all\-zero replacement chunk by the reappeared chunk. If all lost
chunks of a \(dqzero\-patched\(dq file reappear, this effectively \(dqheals\(dq the file.
Consequently, if lost chunks were repaired earlier, it is advised to run
\fB\-\-repair\fP a second time after creating some new backups.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B REPOSITORY_OR_ARCHIVE
repository or archive to check consistency of
.UNINDENT
.SS options
.INDENT 0.0
.TP
@ -153,7 +168,7 @@ See \fIborg\-common(1)\fP for common options of Borg commands.
only perform repository checks
.TP
.B \-\-archives\-only
only perform archive checks
only perform archives checks
.TP
.B \-\-verify\-data
perform cryptographic archive data integrity verification (conflicts with \fB\-\-repository\-only\fP)
@ -161,42 +176,34 @@ perform cryptographic archive data integrity verification (conflicts with \fB\-\
.B \-\-repair
attempt to repair any inconsistencies found
.TP
.B \-\-find\-lost\-archives
attempt to find lost archives
.B \-\-save\-space
work slower, but using less space
.TP
.BI \-\-max\-duration \ SECONDS
perform only a partial repository check for at most SECONDS seconds (default: unlimited)
do only a partial repo check for max. SECONDS seconds (Default: unlimited)
.UNINDENT
.SS Archive filters
.INDENT 0.0
.TP
.BI \-a \ PATTERN\fR,\fB \ \-\-match\-archives \ PATTERN
only consider archives matching all patterns. See \(dqborg help match\-archives\(dq.
.BI \-P \ PREFIX\fR,\fB \ \-\-prefix \ PREFIX
only consider archive names starting with this prefix. (deprecated)
.TP
.BI \-a \ GLOB\fR,\fB \ \-\-glob\-archives \ GLOB
only consider archive names matching the glob. sh: rules apply (without actually using the sh: prefix), see \(dqborg help patterns\(dq.
.TP
.BI \-\-sort\-by \ KEYS
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id, tags, host, user; default is: timestamp
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id; default is: timestamp
.TP
.BI \-\-first \ N
consider the first N archives after other filters are applied
consider first N archives after other filters were applied
.TP
.BI \-\-last \ N
consider the last N archives after other filters are applied
.TP
.BI \-\-oldest \ TIMESPAN
consider archives between the oldest archive\(aqs timestamp and (oldest + TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newest \ TIMESPAN
consider archives between the newest archive\(aqs timestamp and (newest \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-older \ TIMESPAN
consider archives older than (now \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newer \ TIMESPAN
consider archives newer than (now \- TIMESPAN), e.g., 7d or 12m.
consider last N archives after other filters were applied
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,8 +27,8 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-common" "1" "2026-06-16" "" "borg backup tool"
.SH Name
.TH "BORG-COMMON" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-common \- Common options of Borg commands
.SH SYNOPSIS
.INDENT 0.0
@ -65,7 +64,10 @@ format using IEC units (1KiB = 1024B)
Output one JSON object per log line instead of formatted text.
.TP
.BI \-\-lock\-wait \ SECONDS
wait at most SECONDS for acquiring a repository/cache lock (default: 10).
wait at most SECONDS for acquiring a repository/cache lock (default: 1).
.TP
.B \-\-bypass\-lock
Bypass locking mechanism
.TP
.B \-\-show\-version
show/log the borg version
@ -79,24 +81,31 @@ set umask to M (local only, default: 0077)
.BI \-\-remote\-path \ PATH
use PATH as borg executable on the remote (default: \(dqborg\(dq)
.TP
.BI \-\-remote\-ratelimit \ RATE
deprecated, use \fB\-\-upload\-ratelimit\fP instead
.TP
.BI \-\-upload\-ratelimit \ RATE
set network upload rate limit in kiByte/s (default: 0=unlimited)
.TP
.BI \-\-remote\-buffer \ UPLOAD_BUFFER
deprecated, use \fB\-\-upload\-buffer\fP instead
.TP
.BI \-\-upload\-buffer \ UPLOAD_BUFFER
set network upload buffer size in MiB. (default: 0=no buffer)
.TP
.B \-\-consider\-part\-files
treat part files like normal files (e.g. to list/extract them)
.TP
.BI \-\-debug\-profile \ FILE
Write execution profile in Borg format into FILE. For local use a Python\-compatible file can be generated by suffixing FILE with \(dq.pyprof\(dq.
.TP
.BI \-\-rsh \ RSH
Use this command to connect to the \(aqborg serve\(aq process (default: \(aqssh\(aq)
.TP
.BI \-r \ REPO\fR,\fB \ \-\-repo \ REPO
repository to use
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,82 +27,73 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-compact" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-compact \- Collects garbage in the repository.
.TH "BORG-COMPACT" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-compact \- compact segment files in the repository
.SH SYNOPSIS
.sp
borg [common options] compact [options]
borg [common options] compact [options] [REPOSITORY]
.SH DESCRIPTION
.sp
Free repository space by deleting unused chunks.
This command frees repository space by compacting segments.
.sp
\fBborg compact\fP analyzes all existing archives to determine which repository
objects are actually used (referenced). It then deletes all unused objects
from the repository to free space.
Use this regularly to avoid running out of space \- you do not need to use this
after each borg command though. It is especially useful after deleting archives,
because only compaction will really free repository space.
.sp
Unused objects may result from:
.INDENT 0.0
.IP \(bu 2
use of \fBborg delete\fP or \fBborg prune\fP
.IP \(bu 2
interrupted backups (consider retrying the backup before running compact)
.IP \(bu 2
backups of source files that encountered an I/O error mid\-transfer and were skipped
.IP \(bu 2
corruption of the repository (e.g., the archives directory lost entries; see notes below)
.UNINDENT
borg compact does not need a key, so it is possible to invoke it from the
client or also from the server.
.sp
You usually do not want to run \fBborg compact\fP after every write operation, but
either regularly (e.g., once a month, possibly together with \fBborg check\fP) or
when disk space needs to be freed.
Depending on the amount of segments that need compaction, it may take a while,
so consider using the \fB\-\-progress\fP option.
.sp
\fBImportant:\fP
A segment is compacted if the amount of saved space is above the percentage value
given by the \fB\-\-threshold\fP option. If omitted, a threshold of 10% is used.
When using \fB\-\-verbose\fP, borg will output an estimate of the freed space.
.sp
After compacting, it is no longer possible to use \fBborg undelete\fP to recover
previously soft\-deleted archives.
After upgrading borg (server) to 1.2+, you can use \fBborg compact \-\-cleanup\-commits\fP
to clean up the numerous 17byte commit\-only segments that borg 1.1 did not clean up
due to a bug. It is enough to do that once per repository. After cleaning up the
commits, borg will also do a normal compaction.
.sp
\fBborg compact\fP might also delete data from archives that were \(dqlost\(dq due to
archives directory corruption. Such archives could potentially be restored with
\fBborg check \-\-find\-lost\-archives [\-\-repair]\fP, which is slow. You therefore
might not want to do that unless there are signs of lost archives (e.g., when
seeing fatal errors when creating backups or when archives are missing in
\fBborg repo\-list\fP).
.sp
When using the \fB\-\-stats\fP option, borg will internally list all repository
objects to determine their existence and stored size. It will build a fresh
chunks index from that information and cache it in the repository. For some
types of repositories, this might be very slow. It will tell you the sum of
stored object sizes, before and after compaction.
.sp
Without \fB\-\-stats\fP, borg will rely on the cached chunks index to determine
existing object IDs (but there is no stored size information in the index,
thus it cannot compute before/after compaction size statistics).
See \fIseparate_compaction\fP in Additional Notes for more details.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B REPOSITORY
repository to compact
.UNINDENT
.SS options
.INDENT 0.0
.TP
.B \-n\fP,\fB \-\-dry\-run
do not change the repository
.B \-\-cleanup\-commits
cleanup commit\-only 17\-byte segment files
.TP
.B \-s\fP,\fB \-\-stats
print statistics (might be much slower)
.BI \-\-threshold \ PERCENT
set minimum threshold for saved space in PERCENT (Default: 10)
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Compact segments and free repository disk space
$ borg compact
.EE
.nf
.ft C
# compact segments and free repo disk space
$ borg compact /path/to/repo
# same as above plus clean up 17byte commit\-only segments
$ borg compact \-\-cleanup\-commits /path/to/repo
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,76 +0,0 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-completion" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-completion \- Output shell completion script for the given shell.
.SH SYNOPSIS
.sp
borg [common options] completion [options] SHELL
.SH DESCRIPTION
.sp
This command prints a shell completion script for the given shell.
.sp
Please note that for some dynamic completions (like archive IDs), the shell
completion script will call borg to query the repository. This will work best
if that call can be made without prompting for user input, so you may want to
set BORG_REPO and BORG_PASSPHRASE environment variables.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B SHELL
shell to generate completion for (one of: %(choices)s)
.UNINDENT
.SH EXAMPLES
.sp
To activate completion in your current shell session, evaluate the output
of this command. To enable it persistently, add the corresponding line to
your shell\(aqs startup file.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Bash (in ~/.bashrc)
eval \(dq$(borg completion bash)\(dq
# Zsh (in ~/.zshrc)
eval \(dq$(borg completion zsh)\(dq
.EE
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
The Borg Collective
.\" End of generated man page.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,19 +27,19 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-compression" "1" "2026-06-16" "" "borg backup tool"
.SH Name
.TH "BORG-COMPRESSION" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-compression \- Details regarding compression
.SH DESCRIPTION
.sp
It is no problem to mix different compression methods in one repository,
It is no problem to mix different compression methods in one repo,
deduplication is done on the source data chunks (not on the compressed
or encrypted data).
.sp
If some specific chunk was once compressed and stored into the repository, creating
If some specific chunk was once compressed and stored into the repo, creating
another backup that also uses this chunk will not change the stored chunk.
So if you use different compression specs for the backups, whichever stores a
chunk first determines its compression. See also \fBborg recreate\fP\&.
chunk first determines its compression. See also borg recreate.
.sp
Compression is lz4 by default. If you want something else, you have to specify what you want.
.sp
@ -57,6 +56,7 @@ Use lz4 compression. Very high speed, very low compression. (default)
Use zstd (\(dqzstandard\(dq) compression, a modern wide\-range algorithm.
If you do not explicitly give the compression level L (ranging from 1
to 22), it will use level 3.
Archives compressed with zstd are not compatible with borg < 1.1.4.
.TP
.B zlib[,L]
Use zlib (\(dqgz\(dq) compression. Medium speed, medium compression.
@ -78,8 +78,7 @@ Use a built\-in heuristic to decide per chunk whether to compress or not.
The heuristic tries with lz4 whether the data is compressible.
For incompressible data, it will not use compression (uses \(dqnone\(dq).
For compressible data, it uses the given C[,L] compression \- with C[,L]
being any valid compression specifier. This can be helpful for media files
which often cannot be compressed much more.
being any valid compression specifier.
.TP
.B obfuscate,SPEC,C[,L]
Use compressed\-size obfuscation to make fingerprinting attacks based on
@ -104,14 +103,16 @@ Available factors:
.INDENT 7.0
.INDENT 3.5
.sp
.EX
.nf
.ft C
1: 0.01 .. 100
2: 0.1 .. 1,000
3: 1 .. 10,000
4: 10 .. 100,000
5: 100 .. 1,000,000
6: 1,000 .. 10,000,000
.EE
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
@ -119,12 +120,14 @@ Example probabilities for SPEC \fB1\fP:
.INDENT 7.0
.INDENT 3.5
.sp
.EX
.nf
.ft C
90 % 0.01 .. 0.1
9 % 0.1 .. 1
0.9 % 1 .. 10
0.09% 10 .. 100
.EE
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
@ -132,49 +135,40 @@ Example probabilities for SPEC \fB1\fP:
.INDENT 7.0
.INDENT 3.5
.sp
.EX
.nf
.ft C
110: 1kiB (2 ^ (SPEC \- 100))
\&...
120: 1MiB
\&...
123: 8MiB (max.)
.EE
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
\fIPadmé padding\fP (deterministic)
.INDENT 7.0
.INDENT 3.5
.sp
.EX
250: pads to sums of powers of 2, max 12% overhead
.EE
.UNINDENT
.UNINDENT
.sp
Uses the Padmé algorithm to deterministically pad the compressed size to a sum of
powers of 2, limiting overhead to 12%. See \%<https://\:lbarman\:.ch/\:blog/\:padme/> for details.
.UNINDENT
.sp
Examples:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
borg create \-\-compression lz4 \-\-repo REPO ARCHIVE data
borg create \-\-compression zstd \-\-repo REPO ARCHIVE data
borg create \-\-compression zstd,10 \-\-repo REPO ARCHIVE data
borg create \-\-compression zlib \-\-repo REPO ARCHIVE data
borg create \-\-compression zlib,1 \-\-repo REPO ARCHIVE data
borg create \-\-compression auto,lzma,6 \-\-repo REPO ARCHIVE data
.nf
.ft C
borg create \-\-compression lz4 REPO::ARCHIVE data
borg create \-\-compression zstd REPO::ARCHIVE data
borg create \-\-compression zstd,10 REPO::ARCHIVE data
borg create \-\-compression zlib REPO::ARCHIVE data
borg create \-\-compression zlib,1 REPO::ARCHIVE data
borg create \-\-compression auto,lzma,6 REPO::ARCHIVE data
borg create \-\-compression auto,lzma ...
borg create \-\-compression obfuscate,110,none ...
borg create \-\-compression obfuscate,3,auto,zstd,10 ...
borg create \-\-compression obfuscate,2,zstd,6 ...
borg create \-\-compression obfuscate,250,zstd,3 ...
.EE
.ft P
.fi
.UNINDENT
.UNINDENT
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -27,19 +27,19 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "BORG-CONFIG" 1 "2024-07-19" "" "borg backup tool"
.TH "BORG-CONFIG" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-config \- get, set, and delete values in a repository or cache config file
.SH SYNOPSIS
.sp
borg [common options] config [options] [NAME] [VALUE]
borg [common options] config [options] [REPOSITORY] [NAME] [VALUE]
.SH DESCRIPTION
.sp
This command gets and sets options in a local repository or cache config file.
For security reasons, this command only works on local repositories.
.sp
To delete a config value entirely, use \fB\-\-delete\fP\&. To list the values
of the configuration file or the default values, use \fB\-\-list\fP\&. To get an existing
of the configuration file or the default values, use \fB\-\-list\fP\&. To get and existing
key, pass only the key name. To set a key, pass both the key name and
the new value. Keys can be specified in the format \(dqsection.name\(dq or
simply \(dqname\(dq; the section will default to \(dqrepository\(dq and \(dqcache\(dq for
@ -53,13 +53,16 @@ See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B REPOSITORY
repository to configure
.TP
.B NAME
name of config key
.TP
.B VALUE
new value for key
.UNINDENT
.SS optional arguments
.SS options
.INDENT 0.0
.TP
.B \-c\fP,\fB \-\-cache
@ -87,13 +90,13 @@ making changes!
.nf
.ft C
# find cache directory
$ cd ~/.cache/borg/$(borg config id)
$ cd ~/.cache/borg/$(borg config /path/to/repo id)
# reserve some space
$ borg config additional_free_space 2G
$ borg config /path/to/repo additional_free_space 2G
# make a repo append\-only
$ borg config append_only 1
$ borg config /path/to/repo append_only 1
.ft P
.fi
.UNINDENT

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,43 +27,36 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-create" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-create \- Creates a new archive.
.TH "BORG-CREATE" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-create \- Create new archive
.SH SYNOPSIS
.sp
borg [common options] create [options] NAME [PATH...]
borg [common options] create [options] ARCHIVE [PATH...]
.SH DESCRIPTION
.sp
This command creates a backup archive containing all files found while recursively
traversing all specified paths. Paths are added to the archive as they are given,
which means that if relative paths are desired, the command must be run from the correct
traversing all paths specified. Paths are added to the archive as they are given,
that means if relative paths are desired, the command has to be run from the correct
directory.
.sp
The slashdot hack in paths (recursion roots) is triggered by using \fB/./\fP:
\fB/this/gets/stripped/./this/gets/archived\fP means to process that fs object, but
strip the prefix on the left side of \fB\&./\fP from the archived items (in this case,
\fBthis/gets/archived\fP will be the path in the archived item).
.sp
When specifying \(aq\-\(aq as a path, borg will read data from standard input and create a
file named \(aqstdin\(aq in the created archive from that data. In some cases, it is more
appropriate to use \-\-content\-from\-command. See the section \fIReading from stdin\fP
below for details.
When giving \(aq\-\(aq as path, borg will read data from standard input and create a
file \(aqstdin\(aq in the created archive from that data. In some cases it\(aqs more
appropriate to use \-\-content\-from\-command, however. See section \fIReading from
stdin\fP below for details.
.sp
The archive will consume almost no disk space for files or parts of files that
have already been stored in other archives.
.sp
The \fB\-\-tags\fP option can be used to add a list of tags to the new archive.
.sp
The archive name does not need to be unique; you can and should use the same
name for a series of archives. The unique archive identifier is its ID (hash),
and you can abbreviate the ID as long as it is unique.
The archive name needs to be unique. It must not end in \(aq.checkpoint\(aq or
\(aq.checkpoint.N\(aq (with N being a number), because these names are used for
checkpoints and treated in special ways.
.sp
In the archive name, you may use the following placeholders:
{now}, {utcnow}, {fqdn}, {hostname}, {user} and some others.
.sp
Backup speed is increased by not reprocessing files that are already part of
existing archives and were not modified. The detection of unmodified files is
existing archives and weren\(aqt modified. The detection of unmodified files is
done by comparing multiple file metadata values with previous values kept in
the files cache.
.sp
@ -99,30 +91,15 @@ ctime vs. mtime: safety vs. speed
.INDENT 0.0
.IP \(bu 2
ctime is a rather safe way to detect changes to a file (metadata and contents)
as it cannot be set from userspace. But a metadata\-only change will already
as it can not be set from userspace. But, a metadata\-only change will already
update the ctime, so there might be some unnecessary chunking/hashing even
without content changes. Some filesystems do not support ctime (change time).
E.g. doing a chown or chmod to a file will change its ctime.
.IP \(bu 2
mtime usually works and only updates if file contents were changed. But mtime
can be arbitrarily set from userspace, e.g., to set mtime back to the same value
can be arbitrarily set from userspace, e.g. to set mtime back to the same value
it had before a content change happened. This can be used maliciously as well as
well\-meant, but in both cases mtime\-based cache modes can be problematic.
.UNINDENT
.INDENT 0.0
.TP
.B The \fB\-\-files\-changed\fP option controls how Borg detects if a file has changed during backup:
.INDENT 7.0
.IP \(bu 2
ctime (default on POSIX): Use ctime to detect changes. This is the safest option.
Not supported on Windows (ctime is file creation time there).
.IP \(bu 2
mtime (default on Windows): Use mtime to detect changes.
.IP \(bu 2
disabled: Disable the \(dqfile has changed while we backed it up\(dq detection completely.
This is not recommended unless you know what you\(aqre doing, as it could lead to
inconsistent backups if files change during the backup process.
.UNINDENT
well\-meant, but in both cases mtime based cache modes can be problematic.
.UNINDENT
.sp
The mount points of filesystems or filesystem snapshots should be the same for every
@ -130,9 +107,9 @@ creation of a new archive to ensure fast operation. This is because the file cac
is used to determine changed files quickly uses absolute filenames.
If this is not possible, consider creating a bind mount to a stable location.
.sp
The \fB\-\-progress\fP option shows (from left to right) Original and (uncompressed)
deduplicated size (O and U respectively), then the Number of files (N) processed so far,
followed by the currently processed path.
The \fB\-\-progress\fP option shows (from left to right) Original, Compressed and Deduplicated
(O, C and D, respectively), then the Number of files (N) processed so far, followed by
the currently processed path.
.sp
When using \fB\-\-stats\fP, you will get some statistics about how much data was
added \- the \(dqThis Archive\(dq deduplicated size there is most interesting as that is
@ -149,8 +126,8 @@ See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B NAME
specify the archive name
.B ARCHIVE
name of archive to create (must be also a valid directory name)
.TP
.B PATH
paths to archive
@ -165,7 +142,7 @@ do not create a backup archive
print statistics for the created archive
.TP
.B \-\-list
output a verbose list of items (files, dirs, ...)
output verbose list of items (files, dirs, ...)
.TP
.BI \-\-filter \ STATUSCHARS
only display items with the given status characters (see description)
@ -173,30 +150,30 @@ only display items with the given status characters (see description)
.B \-\-json
output stats as JSON. Implies \fB\-\-stats\fP\&.
.TP
.B \-\-no\-cache\-sync
experimental: do not synchronize the cache. Implies not using the files cache.
.TP
.BI \-\-stdin\-name \ NAME
use NAME in archive for stdin data (default: \(aqstdin\(aq)
.TP
.BI \-\-stdin\-user \ USER
set user USER in archive for stdin data (default: do not store user/uid)
set user USER in archive for stdin data (default: \(aqroot\(aq)
.TP
.BI \-\-stdin\-group \ GROUP
set group GROUP in archive for stdin data (default: do not store group/gid)
set group GROUP in archive for stdin data (default: \(aqwheel\(aq)
.TP
.BI \-\-stdin\-mode \ M
set mode to M in archive for stdin data (default: 0660)
.TP
.B \-\-content\-from\-command
interpret PATH as a command and store its stdout. See also the section \(aqReading from stdin\(aq below.
interpret PATH as command and store its stdout. See also section Reading from stdin below.
.TP
.B \-\-paths\-from\-stdin
read DELIM\-separated list of paths to back up from stdin. All control is external: it will back up all files given \- no more, no less.
read DELIM\-separated list of paths to backup from stdin. All control is external: it will back up all files given \- no more, no less.
.TP
.B \-\-paths\-from\-command
interpret PATH as command and treat its output as \fB\-\-paths\-from\-stdin\fP
.TP
.B \-\-paths\-from\-shell\-command
interpret PATH as shell command and treat its output as \fB\-\-paths\-from\-stdin\fP
.TP
.BI \-\-paths\-delimiter \ DELIM
set path delimiter for \fB\-\-paths\-from\-stdin\fP and \fB\-\-paths\-from\-command\fP (default: \fB\en\fP)
.UNINDENT
@ -216,16 +193,16 @@ include/exclude paths matching PATTERN
read include/exclude patterns from PATTERNFILE, one per line
.TP
.B \-\-exclude\-caches
exclude directories that contain a CACHEDIR.TAG file (\%<https://\:www\:.bford\:.info/\:cachedir/\:spec\:.html>)
exclude directories that contain a CACHEDIR.TAG file (\fI\%http://www.bford.info/cachedir/spec.html\fP)
.TP
.BI \-\-exclude\-if\-present \ NAME
exclude directories that are tagged by containing a filesystem object with the given NAME
.TP
.B \-\-keep\-exclude\-tags
if tag objects are specified with \fB\-\-exclude\-if\-present\fP, do not omit the tag objects themselves from the backup archive
if tag objects are specified with \fB\-\-exclude\-if\-present\fP, don\(aqt omit the tag objects themselves from the backup archive
.TP
.B \-\-exclude\-dataless
exclude files flagged DATALESS (macOS: placeholder files whose content is not materialized locally, e.g. not\-downloaded cloud storage files)
.B \-\-exclude\-nodump
exclude files flagged NODUMP
.UNINDENT
.SS Filesystem options
.INDENT 0.0
@ -233,9 +210,15 @@ exclude files flagged DATALESS (macOS: placeholder files whose content is not ma
.B \-x\fP,\fB \-\-one\-file\-system
stay in the same file system and do not store mount points of other file systems \- this might behave different from your expectations, see the description below.
.TP
.B \-\-numeric\-owner
deprecated, use \fB\-\-numeric\-ids\fP instead
.TP
.B \-\-numeric\-ids
only store numeric user and group identifiers
.TP
.B \-\-noatime
do not store atime into archive
.TP
.B \-\-atime
do store atime into archive
.TP
@ -245,6 +228,9 @@ do not store ctime into archive
.B \-\-nobirthtime
do not store birthtime (creation date) into archive
.TP
.B \-\-nobsdflags
deprecated, use \fB\-\-noflags\fP instead
.TP
.B \-\-noflags
do not read and store flags (e.g. NODUMP, IMMUTABLE) into archive
.TP
@ -260,9 +246,6 @@ detect sparse holes in input (supported only by fixed chunker)
.BI \-\-files\-cache \ MODE
operate files cache in MODE. default: ctime,size,inode
.TP
.BI \-\-files\-changed \ MODE
specify how to detect if a file has changed during backup (ctime, mtime, disabled). default: ctime (on Windows: mtime, because ctime is file creation time there).
.TP
.B \-\-read\-special
open and read block and char device files as well as FIFOs as if they were regular files. Also follows symlinks pointing to these kinds of files.
.UNINDENT
@ -273,125 +256,106 @@ open and read block and char device files as well as FIFOs as if they were regul
add a comment text to the archive
.TP
.BI \-\-timestamp \ TIMESTAMP
manually specify the archive creation date/time (yyyy\-mm\-ddThh:mm:ss[(+|\-)HH:MM] format, (+|\-)HH:MM is the UTC offset, default: local time zone). Alternatively, give a reference file/directory.
manually specify the archive creation date/time (UTC, yyyy\-mm\-ddThh:mm:ss format). Alternatively, give a reference file/directory.
.TP
.BI \-c \ SECONDS\fR,\fB \ \-\-checkpoint\-interval \ SECONDS
write checkpoint every SECONDS seconds (Default: 1800)
.TP
.BI \-\-chunker\-params \ PARAMS
specify the chunker parameters (ALGO, CHUNK_MIN_EXP, CHUNK_MAX_EXP, HASH_MASK_BITS, HASH_WINDOW_SIZE). default: buzhash,19,23,21,4095
.TP
.BI \-C \ COMPRESSION\fR,\fB \ \-\-compression \ COMPRESSION
select compression algorithm, see the output of the \(dqborg help compression\(dq command for details.
.TP
.BI \-\-hostname \ HOSTNAME
explicitly set hostname for the archive
.TP
.BI \-\-username \ USERNAME
explicitly set username for the archive
.TP
.BI \-\-tags \ TAG
add tags to archive (comma\-separated or multiple arguments)
.UNINDENT
.SH EXAMPLES
.sp
\fBNote:\fP
.INDENT 0.0
.INDENT 3.5
Archive series and performance: In Borg 2, archives that share the same NAME form an \(dqarchive series\(dq.
The files cache is maintained per series. For best performance on repeated backups, reuse the same
NAME every time you run \fBborg create\fP for the same dataset (e.g. always use \fBmy\-documents\fP).
Frequently changing the NAME (for example by embedding date/time like \fBmy\-documents\-2025\-11\-10\fP)
prevents cache reuse and forces Borg to re\-scan and re\-chunk files, which can make incremental
backups vastly slower. Only vary the NAME if you intentionally want to start a new series.
.sp
If you must vary the archive name but still want cache reuse across names, see the advanced
knobs described in \fIupgradenotes2\fP (\fBBORG_FILES_CACHE_SUFFIX\fP and \fBBORG_FILES_CACHE_TTL\fP),
but the recommended approach is to keep a stable NAME per series.
.UNINDENT
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.nf
.ft C
# Backup ~/Documents into an archive named \(dqmy\-documents\(dq
$ borg create my\-documents ~/Documents
$ borg create /path/to/repo::my\-documents ~/Documents
# same, but list all files as we process them
$ borg create \-\-list my\-documents ~/Documents
# Backup /mnt/disk/docs, but strip path prefix using the slashdot hack
$ borg create \-\-repo /path/to/repo docs /mnt/disk/./docs
$ borg create \-\-list /path/to/repo::my\-documents ~/Documents
# Backup ~/Documents and ~/src but exclude pyc files
$ borg create my\-files \e
$ borg create /path/to/repo::my\-files \e
~/Documents \e
~/src \e
\-\-exclude \(aq*.pyc\(aq
# Backup home directories excluding image thumbnails (i.e. only
# /home/<one directory>/.thumbnails is excluded, not /home/*/*/.thumbnails etc.)
$ borg create my\-files /home \-\-exclude \(aqsh:home/*/.thumbnails\(aq
$ borg create /path/to/repo::my\-files /home \e
\-\-exclude \(aqsh:home/*/.thumbnails\(aq
# Back up the root filesystem into an archive named \(dqroot\-archive\(dq
# Use zlib compression (good, but slow) — default is LZ4 (fast, low compression ratio)
$ borg create \-C zlib,6 \-\-one\-file\-system root\-archive /
# Backup the root filesystem into an archive named \(dqroot\-YYYY\-MM\-DD\(dq
# use zlib compression (good, but slow) \- default is lz4 (fast, low compression ratio)
$ borg create \-C zlib,6 \-\-one\-file\-system /path/to/repo::root\-{now:%Y\-%m\-%d} /
# Backup into an archive name like FQDN\-root
$ borg create \(aq{fqdn}\-root\(aq /
# Backup onto a remote host (\(dqpush\(dq style) via ssh to port 2222,
# logging in as user \(dqborg\(dq and storing into /path/to/repo
$ borg create ssh://borg@backup.example.org:2222/path/to/repo::{fqdn}\-root\-{now} /
# Back up a remote host locally (\(dqpull\(dq style) using SSHFS
# Backup a remote host locally (\(dqpull\(dq style) using sshfs
$ mkdir sshfs\-mount
$ sshfs root@example.com:/ sshfs\-mount
$ cd sshfs\-mount
$ borg create example.com\-root .
$ borg create /path/to/repo::example.com\-root\-{now:%Y\-%m\-%d} .
$ cd ..
$ fusermount \-u sshfs\-mount
# Make a big effort in fine\-grained deduplication (big chunk management
# overhead, needs a lot of RAM and disk space; see the formula in the internals docs):
$ borg create \-\-chunker\-params buzhash,10,23,16,4095 small /smallstuff
# Make a big effort in fine granular deduplication (big chunk management
# overhead, needs a lot of RAM and disk space, see formula in internals
# docs \- same parameters as borg < 1.0 or attic):
$ borg create \-\-chunker\-params buzhash,10,23,16,4095 /path/to/repo::small /smallstuff
# Backup a raw device (must not be active/in use/mounted at that time)
$ borg create \-\-read\-special \-\-chunker\-params fixed,4194304 my\-sdx /dev/sdX
$ borg create \-\-read\-special \-\-chunker\-params fixed,4194304 /path/to/repo::my\-sdx /dev/sdX
# Backup a sparse disk image (must not be active/in use/mounted at that time)
$ borg create \-\-sparse \-\-chunker\-params fixed,4194304 my\-disk my\-disk.raw
$ borg create \-\-sparse \-\-chunker\-params fixed,4194304 /path/to/repo::my\-disk my\-disk.raw
# No compression (none)
$ borg create \-\-compression none arch ~
$ borg create \-\-compression none /path/to/repo::arch ~
# Super fast, low compression (lz4, default)
$ borg create arch ~
$ borg create /path/to/repo::arch ~
# Less fast, higher compression (zlib, N = 0..9)
$ borg create \-\-compression zlib,N arch ~
$ borg create \-\-compression zlib,N /path/to/repo::arch ~
# Even slower, even higher compression (lzma, N = 0..9)
$ borg create \-\-compression lzma,N arch ~
$ borg create \-\-compression lzma,N /path/to/repo::arch ~
# Only compress compressible data with lzma,N (N = 0..9)
$ borg create \-\-compression auto,lzma,N arch ~
$ borg create \-\-compression auto,lzma,N /path/to/repo::arch ~
# Use the short hostname and username as the archive name
$ borg create \(aq{hostname}\-{user}\(aq ~
# Use short hostname, user name and current time in archive name
$ borg create /path/to/repo::{hostname}\-{user}\-{now} ~
# Similar, use the same datetime format that is default as of borg 1.1
$ borg create /path/to/repo::{hostname}\-{user}\-{now:%Y\-%m\-%dT%H:%M:%S} ~
# As above, but add nanoseconds
$ borg create /path/to/repo::{hostname}\-{user}\-{now:%Y\-%m\-%dT%H:%M:%S.%f} ~
# Back up relative paths by moving into the correct directory first
# Backing up relative paths by moving into the correct directory first
$ cd /home/user/Documents
# The root directory of the archive will be \(dqprojectA\(dq
$ borg create \(aqdaily\-projectA\(aq projectA
$ borg create /path/to/repo::daily\-projectA\-{now:%Y\-%m\-%d} projectA
# Use external command to determine files to archive
# Use \-\-paths\-from\-stdin with find to back up only files less than 1 MB in size
$ find ~ \-size \-1000k | borg create \-\-paths\-from\-stdin small\-files\-only
# Use \-\-paths\-from\-command with find to back up files from only a given user
$ borg create \-\-paths\-from\-command joes\-files \-\- find /srv/samba/shared \-user joe
# Use \-\-paths\-from\-shell\-command with find to back up a few files from only a given user \-
# BE VERY CAREFUL AND ONLY USE TRUSTED INPUT FOR THE SHELL COMMAND!
$ borg create \-\-paths\-from\-shell\-command some\-of\-joes\-files \-\- \(dqfind /srv/samba/shared \-user joe | head\(dq
# Use \-\-paths\-from\-stdin with find to only backup files less than 1MB in size
$ find ~ \-size \-1000k | borg create \-\-paths\-from\-stdin /path/to/repo::small\-files\-only
# Use \-\-paths\-from\-command with find to only backup files from a given user
$ borg create \-\-paths\-from\-command /path/to/repo::joes\-files \-\- find /srv/samba/shared \-user joe
# Use \-\-paths\-from\-stdin with \-\-paths\-delimiter (for example, for filenames with newlines in them)
$ find ~ \-size \-1000k \-print0 | borg create \e
\-\-paths\-from\-stdin \e
\-\-paths\-delimiter \(dq\e0\(dq \e
smallfiles\-handle\-newline
.EE
/path/to/repo::smallfiles\-handle\-newline
.ft P
.fi
.UNINDENT
.UNINDENT
.SH NOTES
@ -457,7 +421,7 @@ borg usually just stores their metadata:
.IP \(bu 2
\(aqc\(aq = char device
.IP \(bu 2
\(aqh\(aq = regular file, hard link (to already seen inodes)
\(aqh\(aq = regular file, hardlink (to already seen inodes)
.IP \(bu 2
\(aqs\(aq = symlink
.IP \(bu 2
@ -467,38 +431,26 @@ borg usually just stores their metadata:
Other flags used include:
.INDENT 0.0
.IP \(bu 2
\(aq+\(aq = included, item would be backed up (if not in dry\-run mode)
.IP \(bu 2
\(aq\-\(aq = excluded, item would not be / was not backed up
.IP \(bu 2
\(aqi\(aq = backup data was read from standard input (stdin)
.IP \(bu 2
\(aq\-\(aq = dry run, item was \fInot\fP backed up
.IP \(bu 2
\(aqx\(aq = excluded, item was \fInot\fP backed up
.IP \(bu 2
\(aq?\(aq = missing status code (if you see this, please file a bug report!)
.UNINDENT
.SS Errors and (incomplete) archives
.sp
If an error happens during archive creation (e.g. some file could not be read
due to a permission error or some other OS error), borg will log a warning or
an error (depending on the type of issue) and continue with the next item.
.sp
At the end of the backup, if there were any such issues, borg will exit with
a non\-zero exit code (usually 1 for warnings).
.sp
\fBThe archive is still saved even if warnings or errors occurred\fP, but it will
only contain the data borg was able to read successfully. It is like a
checkpoint (see below), but with a user\-given name.
.sp
You should always check the backup logs and the exit code of the borg command.
.SS Reading backup data from stdin
.SS Reading from stdin
.sp
There are two methods to read from stdin. Either specify \fB\-\fP as path and
pipe directly to borg:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
backup\-vm \-\-id myvm \-\-stdout | borg create \-\-repo REPO ARCHIVE \-
.EE
.nf
.ft C
backup\-vm \-\-id myvm \-\-stdout | borg create REPO::ARCHIVE \-
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
@ -509,9 +461,11 @@ to the command:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
borg create \-\-content\-from\-command \-\-repo REPO ARCHIVE \-\- backup\-vm \-\-id myvm \-\-stdout
.EE
.nf
.ft C
borg create \-\-content\-from\-command REPO::ARCHIVE \-\- backup\-vm \-\-id myvm \-\-stdout
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
@ -532,22 +486,10 @@ creation a bit.
.sp
By default, the content read from stdin is stored in a file called \(aqstdin\(aq.
Use \fB\-\-stdin\-name\fP to change the name.
.SS Feeding all file paths from externally
.sp
Usually, you give a starting path (recursion root) to borg and then borg
automatically recurses, finds and backs up all fs objects contained in
there (optionally considering include/exclude rules).
.sp
If you need more control and you want to give every single fs object path
to borg (maybe implementing your own recursion or your own rules), you can use
\fB\-\-paths\-from\-stdin\fP, \fB\-\-paths\-from\-command\fP or \fB\-\-paths\-from\-shell\-command\fP
(with the latter two, borg will fail to create an archive should the command fail).
.sp
Borg supports paths with the slashdot hack to strip path prefixes here also.
So, be careful not to unintentionally trigger that.
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-delete(1)\fP, \fIborg\-prune(1)\fP, \fIborg\-check(1)\fP, \fIborg\-patterns(1)\fP, \fIborg\-placeholders(1)\fP, \fIborg\-compression(1)\fP, \fIborg\-repo\-create(1)\fP
.SH Author
\fIborg\-common(1)\fP, \fIborg\-delete(1)\fP, \fIborg\-prune(1)\fP, \fIborg\-check(1)\fP, \fIborg\-patterns(1)\fP, \fIborg\-placeholders(1)\fP, \fIborg\-compression(1)\fP
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,103 +27,130 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-delete" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-delete \- Deletes archives.
.TH "BORG-DELETE" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-delete \- Delete an existing repository or archives
.SH SYNOPSIS
.sp
borg [common options] delete [options] [NAME]
borg [common options] delete [options] [REPOSITORY_OR_ARCHIVE] [ARCHIVE...]
.SH DESCRIPTION
.sp
This command soft\-deletes archives from the repository.
This command deletes an archive from the repository or the complete repository.
.sp
Important:
.INDENT 0.0
.IP \(bu 2
The delete command will only mark archives for deletion (\(dqsoft\-deletion\(dq),
repository disk space is \fBnot\fP freed until you run \fBborg compact\fP\&.
.IP \(bu 2
You can use \fBborg undelete\fP to undelete archives, but only until
Important: When deleting archives, repository disk space is \fBnot\fP freed until
you run \fBborg compact\fP\&.
.UNINDENT
.sp
When you delete a complete repository, the security info and local cache for it
(if any) are also deleted. Alternatively, you can delete just the local cache
with the \fB\-\-cache\-only\fP option, or keep the security info with the
\fB\-\-keep\-security\-info\fP option.
.sp
When in doubt, use \fB\-\-dry\-run \-\-list\fP to see what would be deleted.
.sp
You can delete multiple archives by specifying a match pattern using
the \fB\-\-match\-archives PATTERN\fP option (for more information on these
patterns, see \fIborg_patterns\fP).
When using \fB\-\-stats\fP, you will get some statistics about how much data was
deleted \- the \(dqDeleted data\(dq deduplicated size there is most interesting as
that is how much your repository will shrink.
Please note that the \(dqAll archives\(dq stats refer to the state after deletion.
.sp
You can delete multiple archives by specifying a shell pattern to match
multiple archives using the \fB\-\-glob\-archives GLOB\fP option (for more info on
these patterns, see \fIborg_patterns\fP).
.sp
To avoid accidentally deleting archives, especially when using glob patterns,
it might be helpful to use the \fB\-\-dry\-run\fP to test out the command without
actually making any changes to the repository.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B NAME
specify the archive name
.B REPOSITORY_OR_ARCHIVE
repository or archive to delete
.TP
.B ARCHIVE
archives to delete
.UNINDENT
.SS options
.INDENT 0.0
.TP
.B \-n\fP,\fB \-\-dry\-run
do not change the repository
do not change repository
.TP
.B \-\-list
output a verbose list of archives
output verbose list of archives
.TP
.B \-s\fP,\fB \-\-stats
print statistics for the deleted archive
.TP
.B \-\-cache\-only
delete only the local cache for the given repository
.TP
.B \-\-force
force deletion of corrupted archives, use \fB\-\-force \-\-force\fP in case \fB\-\-force\fP does not work.
.TP
.B \-\-keep\-security\-info
keep the local security info when deleting a repository
.TP
.B \-\-save\-space
work slower, but using less space
.TP
.BI \-c \ SECONDS\fR,\fB \ \-\-checkpoint\-interval \ SECONDS
write checkpoint every SECONDS seconds (Default: 1800)
.UNINDENT
.SS Archive filters
.INDENT 0.0
.TP
.BI \-a \ PATTERN\fR,\fB \ \-\-match\-archives \ PATTERN
only consider archives matching all patterns. See \(dqborg help match\-archives\(dq.
.BI \-P \ PREFIX\fR,\fB \ \-\-prefix \ PREFIX
only consider archive names starting with this prefix. (deprecated)
.TP
.BI \-a \ GLOB\fR,\fB \ \-\-glob\-archives \ GLOB
only consider archive names matching the glob. sh: rules apply (without actually using the sh: prefix), see \(dqborg help patterns\(dq.
.TP
.BI \-\-sort\-by \ KEYS
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id, tags, host, user; default is: timestamp
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id; default is: timestamp
.TP
.BI \-\-first \ N
consider the first N archives after other filters are applied
consider first N archives after other filters were applied
.TP
.BI \-\-last \ N
consider the last N archives after other filters are applied
.TP
.BI \-\-oldest \ TIMESPAN
consider archives between the oldest archive\(aqs timestamp and (oldest + TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newest \ TIMESPAN
consider archives between the newest archive\(aqs timestamp and (newest \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-older \ TIMESPAN
consider archives older than (now \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newer \ TIMESPAN
consider archives newer than (now \- TIMESPAN), e.g., 7d or 12m.
consider last N archives after other filters were applied
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Delete all backup archives named \(dqkenny\-files\(dq:
$ borg delete \-a kenny\-files
# Actually free disk space:
$ borg compact
.nf
.ft C
# delete a single backup archive:
$ borg delete /path/to/repo::Monday
# actually free disk space:
$ borg compact /path/to/repo
# Delete a specific backup archive using its unique archive ID prefix
$ borg delete aid:d34db33f
# delete all archives whose names begin with the machine\(aqs hostname followed by \(dq\-\(dq
$ borg delete \-\-glob\-archives \(aq{hostname}\-*\(aq /path/to/repo
# Delete all archives whose names begin with the machine\(aqs hostname followed by \(dq\-\(dq
$ borg delete \-a \(aqsh:{hostname}\-*\(aq
# delete all archives whose names contain \(dq\-2012\-\(dq
$ borg delete \-\-glob\-archives \(aq*\-2012\-*\(aq /path/to/repo
# Delete all archives whose names contain \(dq\-2012\-\(dq
$ borg delete \-a \(aqsh:*\-2012\-*\(aq
# see what would be deleted if delete was run without \-\-dry\-run
$ borg delete \-\-list \-\-dry\-run \-a \(aq*\-May\-*\(aq /path/to/repo
# See what would be deleted if delete was run without \-\-dry\-run
$ borg delete \-\-list \-\-dry\-run \-a \(aqsh:*\-May\-*\(aq
.EE
# delete the whole repository and the related local cache:
$ borg delete /path/to/repo
You requested to completely DELETE the repository *including* all archives it contains:
repo Mon, 2016\-02\-15 19:26:54
root\-2016\-02\-15 Mon, 2016\-02\-15 19:36:29
newname Mon, 2016\-02\-15 19:50:19
Type \(aqYES\(aq if you understand this and want to continue: YES
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-compact(1)\fP, \fIborg\-repo\-delete(1)\fP
.SH Author
\fIborg\-common(1)\fP, \fIborg\-compact(1)\fP
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,52 +27,65 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-diff" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-diff \- Finds differences between two archives.
.TH "BORG-DIFF" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-diff \- Diff contents of two archives
.SH SYNOPSIS
.sp
borg [common options] diff [options] ARCHIVE1 ARCHIVE2 [PATH...]
borg [common options] diff [options] REPO::ARCHIVE1 ARCHIVE2 [PATH...]
.SH DESCRIPTION
.sp
This command finds differences (file contents, metadata) between ARCHIVE1 and ARCHIVE2.
This command finds differences (file contents, user/group/mode) between archives.
.sp
For more help on include/exclude patterns, see the output of the \fIborg_patterns\fP command.
A repository location and an archive name must be specified for REPO::ARCHIVE1.
ARCHIVE2 is just another archive name in same repository (no repository location
allowed).
.sp
For archives created with Borg 1.1 or newer diff automatically detects whether
the archives are created with the same chunker params. If so, only chunk IDs
are compared, which is very fast.
.sp
For archives prior to Borg 1.1 chunk contents are compared by default.
If you did not create the archives with different chunker params,
pass \fB\-\-same\-chunker\-params\fP\&.
Note that the chunker params changed from Borg 0.xx to 1.0.
.sp
For more help on include/exclude patterns, see the \fIborg_patterns\fP command output.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B ARCHIVE1
ARCHIVE1 name
.B REPO::ARCHIVE1
repository location and ARCHIVE1 name
.TP
.B ARCHIVE2
ARCHIVE2 name
ARCHIVE2 name (no repository location allowed)
.TP
.B PATH
paths of items inside the archives to compare; patterns are supported.
paths of items inside the archives to compare; patterns are supported
.UNINDENT
.SS options
.INDENT 0.0
.TP
.B \-\-numeric\-owner
deprecated, use \fB\-\-numeric\-ids\fP instead
.TP
.B \-\-numeric\-ids
only consider numeric user and group identifiers
.TP
.B \-\-same\-chunker\-params
override the check of chunker parameters
Override check of chunker parameters.
.TP
.BI \-\-format \ FORMAT
specify format for differences between archives (default: \(dq{change} {path}{NL}\(dq)
.TP
.B \-\-json\-lines
Format output as JSON Lines.
.TP
.B \-\-sort\-by
Sort output by comma\-separated fields (e.g., \(aq>size_added,path\(aq).
.B \-\-sort
Sort the output lines by file path.
.TP
.B \-\-content\-only
Only compare differences in content (exclude metadata differences)
.TP
.B \-\-json\-lines
Format output as JSON Lines.
.UNINDENT
.SS Include/Exclude options
.INDENT 0.0
@ -94,167 +106,54 @@ read include/exclude patterns from PATTERNFILE, one per line
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ borg diff archive1 archive2
.nf
.ft C
$ borg init \-e=none testrepo
$ mkdir testdir
$ cd testdir
$ echo asdf > file1
$ dd if=/dev/urandom bs=1M count=4 > file2
$ touch file3
$ borg create ../testrepo::archive1 .
$ chmod a+x file1
$ echo \(dqsomething\(dq >> file2
$ borg create ../testrepo::archive2 .
$ echo \(dqtesting 123\(dq >> file1
$ rm file3
$ touch file4
$ borg create ../testrepo::archive3 .
$ cd ..
$ borg diff testrepo::archive1 archive2
[\-rw\-r\-\-r\-\- \-> \-rwxr\-xr\-x] file1
+135 B \-252 B file2
$ borg diff testrepo::archive2 archive3
+17 B \-5 B file1
added 0 B file4
removed 0 B file3
$ borg diff testrepo::archive1 archive3
+17 B \-5 B [\-rw\-r\-\-r\-\- \-> \-rwxr\-xr\-x] file1
+135 B \-252 B file2
added 0 B file4
removed 0 B file3
$ borg diff archive1 archive2
$ borg diff \-\-json\-lines testrepo::archive1 archive3
{\(dqpath\(dq: \(dqfile1\(dq, \(dqchanges\(dq: [{\(dqtype\(dq: \(dqmodified\(dq, \(dqadded\(dq: 17, \(dqremoved\(dq: 5}, {\(dqtype\(dq: \(dqmode\(dq, \(dqold_mode\(dq: \(dq\-rw\-r\-\-r\-\-\(dq, \(dqnew_mode\(dq: \(dq\-rwxr\-xr\-x\(dq}]}
{\(dqpath\(dq: \(dqfile2\(dq, \(dqchanges\(dq: [{\(dqtype\(dq: \(dqmodified\(dq, \(dqadded\(dq: 135, \(dqremoved\(dq: 252}]}
{\(dqpath\(dq: \(dqfile4\(dq, \(dqchanges\(dq: [{\(dqtype\(dq: \(dqadded\(dq, \(dqsize\(dq: 0}]}
{\(dqpath\(dq: \(dqfile3\(dq, \(dqchanges\(dq: [{\(dqtype\(dq: \(dqremoved\(dq, \(dqsize\(dq: 0}]}
# Use \-\-sort\-by with a comma\-separated list; sorts apply stably from last to first.
# Here: primary by net size change descending, tie\-breaker by path ascending
$ borg diff \-\-sort\-by=\(dq>size_diff,path\(dq archive1 archive2
+17 B \-5 B [\-rw\-r\-\-r\-\- \-> \-rwxr\-xr\-x] file1
removed 0 B file3
added 0 B file4
+135 B \-252 B file2
.EE
{\(dqpath\(dq: \(dqfile3\(dq, \(dqchanges\(dq: [{\(dqtype\(dq: \(dqremoved\(dq, \(dqsize\(dq: 0}]
.ft P
.fi
.UNINDENT
.UNINDENT
.SH NOTES
.SS The FORMAT specifier syntax
.sp
The \fB\-\-format\fP option uses Python\(aqs format string syntax \%<https://\:docs\:.python\:.org/\:3\:.11/\:library/\:string\:.html#\:formatstrings>\&.
.sp
Examples:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ borg diff \-\-format \(aq{content:30} {path}{NL}\(aq ArchiveFoo ArchiveBar
modified: +4.1 kB \-1.0 kB file\-diff
\&...
# {VAR:<NUMBER} \- pad to NUMBER columns left\-aligned.
# {VAR:>NUMBER} \- pad to NUMBER columns right\-aligned.
$ borg diff \-\-format \(aq{content:>30} {path}{NL}\(aq ArchiveFoo ArchiveBar
modified: +4.1 kB \-1.0 kB file\-diff
\&...
.EE
.UNINDENT
.UNINDENT
.sp
The following keys are always available:
\- NEWLINE: OS dependent line separator
\- NL: alias of NEWLINE
\- NUL: NUL character for creating print0 / xargs \-0 like output
\- SPACE: space character
\- TAB: tab character
\- CR: carriage return character
\- LF: line feed character
.sp
Keys available only when showing differences between archives:
.INDENT 0.0
.IP \(bu 2
path: archived file path
.IP \(bu 2
change: all available changes
.IP \(bu 2
content: file content change
.IP \(bu 2
mode: file mode change
.IP \(bu 2
type: file type change
.IP \(bu 2
owner: file owner (user/group) change
.IP \(bu 2
group: file group change
.IP \(bu 2
user: file user change
.IP \(bu 2
link: file link change
.IP \(bu 2
directory: file directory change
.IP \(bu 2
blkdev: file block device change
.IP \(bu 2
chrdev: file character device change
.IP \(bu 2
fifo: file fifo change
.IP \(bu 2
mtime: file modification time change
.IP \(bu 2
ctime: file change time change
.IP \(bu 2
isomtime: file modification time change (ISO 8601)
.IP \(bu 2
isoctime: file creation time change (ISO 8601)
.UNINDENT
.SS What is compared
.sp
For each matching item in both archives, Borg reports:
.INDENT 0.0
.IP \(bu 2
Content changes: total added/removed bytes within files. If chunker parameters are comparable,
Borg compares chunk IDs quickly; otherwise, it compares the content.
.IP \(bu 2
Metadata changes: user, group, mode, and other metadata shown inline, like
\(dq[old_mode \-> new_mode]\(dq for mode changes. Use \fB\-\-content\-only\fP to suppress metadata changes.
.IP \(bu 2
Added/removed items: printed as \(dqadded SIZE path\(dq or \(dqremoved SIZE path\(dq.
.UNINDENT
.SS Output formats
.sp
The default (text) output shows one line per changed path, e.g.:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
+135 B \-252 B [ \-rw\-r\-\-r\-\- \-> \-rwxr\-xr\-x ] path/to/file
.EE
.UNINDENT
.UNINDENT
.sp
JSON Lines output (\fB\-\-json\-lines\fP) prints one JSON object per changed path, e.g.:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{\(dqpath\(dq: \(dqPATH\(dq, \(dqchanges\(dq: [
{\(dqtype\(dq: \(dqmodified\(dq, \(dqadded\(dq: BYTES, \(dqremoved\(dq: BYTES},
{\(dqtype\(dq: \(dqmode\(dq, \(dqold_mode\(dq: \(dq\-rw\-r\-\-r\-\-\(dq, \(dqnew_mode\(dq: \(dq\-rwxr\-xr\-x\(dq},
{\(dqtype\(dq: \(dqadded\(dq, \(dqsize\(dq: SIZE},
{\(dqtype\(dq: \(dqremoved\(dq, \(dqsize\(dq: SIZE}
]}
.EE
.UNINDENT
.UNINDENT
.SS Sorting
.sp
Use \fB\-\-sort\-by FIELDS\fP where FIELDS is a comma\-separated list of fields.
Sorts are applied stably from last to first in the given list. Prepend \(dq>\(dq for
descending, \(dq<\(dq (or no prefix) for ascending, for example \fB\-\-sort\-by=\(dq>size_added,path\(dq\fP\&.
Supported fields include:
.INDENT 0.0
.IP \(bu 2
path: the item path
.IP \(bu 2
size_added: total bytes added for the item content
.IP \(bu 2
size_removed: total bytes removed for the item content
.IP \(bu 2
size_diff: size_added \- size_removed (net content change)
.IP \(bu 2
size: size of the item as stored in ARCHIVE2 (0 for removed items)
.IP \(bu 2
user, group, uid, gid, ctime, mtime: taken from the item state in ARCHIVE2 when present
.IP \(bu 2
ctime_diff, mtime_diff: timestamp difference (ARCHIVE2 \- ARCHIVE1)
.UNINDENT
.SS Performance considerations
.sp
diff automatically detects whether the archives were created with the same chunker
parameters. If so, only chunk IDs are compared, which is very fast.
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,4 @@
'\" t
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -29,12 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-export-tar" "1" "2026-06-16" "" "borg backup tool"
.SH Name
.TH "BORG-EXPORT-TAR" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-export-tar \- Export archive contents as a tarball
.SH SYNOPSIS
.sp
borg [common options] export\-tar [options] NAME FILE [PATH...]
borg [common options] export\-tar [options] ARCHIVE FILE [PATH...]
.SH DESCRIPTION
.sp
This command creates a tarball from an archive.
@ -61,44 +59,12 @@ Alternatively, a \fB\-\-tar\-filter\fP program may be explicitly specified. It s
read the uncompressed tar stream from stdin and write a compressed/filtered
tar stream to stdout.
.sp
Depending on the \fB\-\-tar\-format\fP option, these formats are created:
.TS
box center;
l|l|l.
T{
\-\-tar\-format
T} T{
Specification
T} T{
Metadata
T}
_
T{
BORG
T} T{
BORG specific, like PAX
T} T{
all as supported by borg
T}
_
T{
PAX
T} T{
POSIX.1\-2001 (pax) format
T} T{
GNU + atime/ctime/mtime ns
+ xattrs
T}
_
T{
GNU
T} T{
GNU tar format
T} T{
mtime s, no atime/ctime,
no ACLs/xattrs/bsdflags
T}
.TE
The generated tarball uses the GNU tar format.
.sp
export\-tar is a lossy conversion:
BSD flags, ACLs, extended attributes (xattrs), atime and ctime are not exported.
Timestamp resolution is limited to whole seconds, not the nanosecond resolution
otherwise supported by Borg.
.sp
A \fB\-\-sparse\fP option (as found in borg extract) is not supported.
.sp
@ -116,8 +82,8 @@ See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B NAME
specify the archive name
.B ARCHIVE
archive to export
.TP
.B FILE
output tar file. \(dq\-\(dq to write to stdout instead.
@ -133,9 +99,6 @@ filter program to pipe data through
.TP
.B \-\-list
output verbose list of items (files, dirs, ...)
.TP
.BI \-\-tar\-format \ FMT
select tar format: BORG, PAX or GNU
.UNINDENT
.SS Include/Exclude options
.INDENT 0.0
@ -155,9 +118,35 @@ read include/exclude patterns from PATTERNFILE, one per line
.BI \-\-strip\-components \ NUMBER
Remove the specified number of leading path elements. Paths with fewer elements will be silently skipped.
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
# export as uncompressed tar
$ borg export\-tar /path/to/repo::Monday Monday.tar
# exclude some types, compress using gzip
$ borg export\-tar /path/to/repo::Monday Monday.tar.gz \-\-exclude \(aq*.so\(aq
# use higher compression level with gzip
$ borg export\-tar \-\-tar\-filter=\(dqgzip \-9\(dq testrepo::linux Monday.tar.gz
# export a tar, but instead of storing it on disk,
# upload it to a remote site using curl.
$ borg export\-tar /path/to/repo::Monday \- | curl \-\-data\-binary @\- https://somewhere/to/POST
# remote extraction via \(dqtarpipe\(dq
$ borg export\-tar /path/to/repo::Monday \- | ssh somewhere \(dqcd extracted; tar x\(dq
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,41 +27,37 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-extract" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-extract \- Extracts archive contents.
.TH "BORG-EXTRACT" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-extract \- Extract archive contents
.SH SYNOPSIS
.sp
borg [common options] extract [options] NAME [PATH...]
borg [common options] extract [options] ARCHIVE [PATH...]
.SH DESCRIPTION
.sp
This command extracts the contents of an archive.
This command extracts the contents of an archive. By default the entire
archive is extracted but a subset of files and directories can be selected
by passing a list of \fBPATHs\fP as arguments. The file selection can further
be restricted by using the \fB\-\-exclude\fP option.
.sp
By default, the entire archive is extracted, but a subset of files and directories
can be selected by passing a list of \fBPATH\fP arguments. The default interpretation
for the paths to extract is \fIpp:\fP which is a literal path\-prefix match. If you want
to use e.g. a wildcard, you must select a different pattern style such as \fIsh:\fP or
\fIfm:\fP\&. See \fIborg_patterns\fP for more information.
.sp
The file selection can be further restricted by using the \fB\-\-exclude\fP option.
For more help on include/exclude patterns, see the \fIborg_patterns\fP command output.
.sp
By using \fB\-\-dry\-run\fP, you can do all extraction steps except actually writing the
output data: reading metadata and data chunks from the repository, checking the hash/HMAC,
decrypting, and decompressing.
output data: reading metadata and data chunks from the repo, checking the hash/hmac,
decrypting, decompressing.
.sp
\fB\-\-progress\fP can be slower than no progress display, since it makes one additional
pass over the archive metadata.
.sp
\fBNote:\fP
\fBNOTE:\fP
.INDENT 0.0
.INDENT 3.5
Currently, extract always writes into the current working directory (\(dq.\(dq),
so make sure you \fBcd\fP to the right place before calling \fBborg extract\fP\&.
.sp
When parent directories are not extracted (because of using file/directory selection
or any other reason), Borg cannot restore parent directories\(aq metadata, e.g., owner,
group, permissions, etc.
or any other reason), borg can not restore parent directories\(aq metadata, e.g. owner,
group, permission, etc.
.UNINDENT
.UNINDENT
.SH OPTIONS
@ -71,8 +66,8 @@ See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B NAME
specify the archive name
.B ARCHIVE
archive to extract
.TP
.B PATH
paths to extract; patterns are supported
@ -81,13 +76,19 @@ paths to extract; patterns are supported
.INDENT 0.0
.TP
.B \-\-list
output a verbose list of items (files, dirs, ...)
output verbose list of items (files, dirs, ...)
.TP
.B \-n\fP,\fB \-\-dry\-run
do not actually change any files
.TP
.B \-\-numeric\-owner
deprecated, use \fB\-\-numeric\-ids\fP instead
.TP
.B \-\-numeric\-ids
only use numeric user and group identifiers
only obey numeric user and group identifiers
.TP
.B \-\-nobsdflags
deprecated, use \fB\-\-noflags\fP instead
.TP
.B \-\-noflags
do not extract/set flags (e.g. NODUMP, IMMUTABLE)
@ -102,10 +103,7 @@ do not extract/set xattrs
write all extracted data to stdout
.TP
.B \-\-sparse
create holes in the output sparse file from all\-zero chunks
.TP
.B \-\-continue
continue a previously interrupted extraction of the same archive
create holes in output sparse file from all\-zero chunks
.UNINDENT
.SS Include/Exclude options
.INDENT 0.0
@ -129,33 +127,33 @@ Remove the specified number of leading path elements. Paths with fewer elements
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.nf
.ft C
# Extract entire archive
$ borg extract my\-files
$ borg extract /path/to/repo::my\-files
# Extract entire archive and list files while processing
$ borg extract \-\-list my\-files
$ borg extract \-\-list /path/to/repo::my\-files
# Verify whether an archive could be successfully extracted, but do not write files to disk
$ borg extract \-\-dry\-run my\-files
$ borg extract \-\-dry\-run /path/to/repo::my\-files
# Extract the \(dqsrc\(dq directory
$ borg extract my\-files home/USERNAME/src
$ borg extract /path/to/repo::my\-files home/USERNAME/src
# Extract the \(dqsrc\(dq directory but exclude object files
$ borg extract my\-files home/USERNAME/src \-\-exclude \(aq*.o\(aq
# Extract only the C files
$ borg extract my\-files \(aqsh:home/USERNAME/src/*.c\(aq
$ borg extract /path/to/repo::my\-files home/USERNAME/src \-\-exclude \(aq*.o\(aq
# Restore a raw device (must not be active/in use/mounted at that time)
$ borg extract \-\-stdout my\-sdx | dd of=/dev/sdx bs=10M
.EE
$ borg extract \-\-stdout /path/to/repo::my\-sdx | dd of=/dev/sdx bs=10M
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-mount(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,12 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-import-tar" "1" "2026-06-16" "" "borg backup tool"
.SH Name
.TH "BORG-IMPORT-TAR" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-import-tar \- Create a backup archive from a tarball
.SH SYNOPSIS
.sp
borg [common options] import\-tar [options] NAME TARFILE
borg [common options] import\-tar [options] ARCHIVE TARFILE
.SH DESCRIPTION
.sp
This command creates a backup archive from a tarball.
@ -62,25 +61,15 @@ stdout.
Most documentation of borg create applies. Note that this command does not
support excluding files.
.sp
import\-tar is a lossy conversion:
BSD flags, ACLs, extended attributes (xattrs), atime and ctime are not exported.
Timestamp resolution is limited to whole seconds, not the nanosecond resolution
otherwise supported by Borg.
.sp
A \fB\-\-sparse\fP option (as found in borg create) is not supported.
.sp
About tar formats and metadata conservation or loss, please see \fBborg export\-tar\fP\&.
.sp
import\-tar reads these tar formats:
.INDENT 0.0
.IP \(bu 2
BORG: borg specific (PAX\-based)
.IP \(bu 2
PAX: POSIX.1\-2001
.IP \(bu 2
GNU: GNU tar
.IP \(bu 2
POSIX.1\-1988 (ustar)
.IP \(bu 2
UNIX V7 tar
.IP \(bu 2
SunOS tar with extended attributes
.UNINDENT
import\-tar reads POSIX.1\-1988 (ustar), POSIX.1\-2001 (pax), GNU tar, UNIX V7 tar
and SunOS tar with extended attributes.
.sp
To import multiple tarballs into a single archive, they can be simply
concatenated (e.g. using \(dqcat\(dq) into a single file, and imported with an
@ -91,8 +80,8 @@ See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B NAME
specify the archive name
.B ARCHIVE
name of archive to create (must be also a valid directory name)
.TP
.B TARFILE
input tar file. \(dq\-\(dq to read from stdin instead.
@ -125,7 +114,10 @@ ignore zero\-filled blocks in the input tarball
add a comment text to the archive
.TP
.BI \-\-timestamp \ TIMESTAMP
manually specify the archive creation date/time (yyyy\-mm\-ddThh:mm:ss[(+|\-)HH:MM] format, (+|\-)HH:MM is the UTC offset, default: local time zone). Alternatively, give a reference file/directory.
manually specify the archive creation date/time (UTC, yyyy\-mm\-ddThh:mm:ss format). alternatively, give a reference file/directory.
.TP
.BI \-c \ SECONDS\fR,\fB \ \-\-checkpoint\-interval \ SECONDS
write checkpoint every SECONDS seconds (Default: 1800)
.TP
.BI \-\-chunker\-params \ PARAMS
specify the chunker parameters (ALGO, CHUNK_MIN_EXP, CHUNK_MAX_EXP, HASH_MASK_BITS, HASH_WINDOW_SIZE). default: buzhash,19,23,21,4095
@ -133,79 +125,10 @@ specify the chunker parameters (ALGO, CHUNK_MIN_EXP, CHUNK_MAX_EXP, HASH_MASK_BI
.BI \-C \ COMPRESSION\fR,\fB \ \-\-compression \ COMPRESSION
select compression algorithm, see the output of the \(dqborg help compression\(dq command for details.
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Export as an uncompressed tar archive
$ borg export\-tar Monday Monday.tar
# Import an uncompressed tar archive
$ borg import\-tar Monday Monday.tar
# Exclude some file types and compress using gzip
$ borg export\-tar Monday Monday.tar.gz \-\-exclude \(aq*.so\(aq
# Use a higher compression level with gzip
$ borg export\-tar \-\-tar\-filter=\(dqgzip \-9\(dq Monday Monday.tar.gz
# Copy an archive from repoA to repoB
$ borg \-r repoA export\-tar \-\-tar\-format=BORG archive \- | borg \-r repoB import\-tar archive \-
# Export a tar, but instead of storing it on disk, upload it to a remote site using curl
$ borg export\-tar Monday \- | curl \-\-data\-binary @\- https://somewhere/to/POST
# Remote extraction via \(aqtarpipe\(aq
$ borg export\-tar Monday \- | ssh somewhere \(dqcd extracted; tar x\(dq
.EE
.UNINDENT
.UNINDENT
.SS Archives transfer script
.sp
Outputs a script that copies all archives from repo1 to repo2:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
for N I T in \(gaborg list \-\-format=\(aq{archive} {id} {time:%Y\-%m\-%dT%H:%M:%S}{NL}\(aq\(ga
do
echo \(dqborg \-r repo1 export\-tar \-\-tar\-format=BORG aid:$I \- | borg \-r repo2 import\-tar \-\-timestamp=$T $N \-\(dq
done
.EE
.UNINDENT
.UNINDENT
.sp
Kept:
.INDENT 0.0
.IP \(bu 2
archive name, archive timestamp
.IP \(bu 2
archive contents (all items with metadata and data)
.UNINDENT
.sp
Lost:
.INDENT 0.0
.IP \(bu 2
some archive metadata (like the original command line, execution time, etc.)
.UNINDENT
.sp
Please note:
.INDENT 0.0
.IP \(bu 2
all data goes over that pipe, again and again for every archive
.IP \(bu 2
the pipe is dumb, there is no data or transfer time reduction there due to deduplication
.IP \(bu 2
maybe add compression
.IP \(bu 2
pipe over ssh for remote transfer
.IP \(bu 2
no special sparse file support
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,32 +27,37 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-info" "1" "2026-06-16" "" "borg backup tool"
.SH Name
.TH "BORG-INFO" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-info \- Show archive details such as disk space used
.SH SYNOPSIS
.sp
borg [common options] info [options] [NAME]
borg [common options] info [options] [REPOSITORY_OR_ARCHIVE]
.SH DESCRIPTION
.sp
This command displays detailed information about the specified archive.
This command displays detailed information about the specified archive or repository.
.sp
Please note that the deduplicated sizes of the individual archives do not add
up to the deduplicated size of the repository (\(dqall archives\(dq), because the two
mean different things:
are meaning different things:
.sp
This archive / deduplicated size = amount of data stored ONLY for this archive
= unique chunks of this archive.
All archives / deduplicated size = amount of data stored in the repository
All archives / deduplicated size = amount of data stored in the repo
= all chunks in the repository.
.sp
Borg archives can only contain a limited amount of file metadata.
The size of an archive relative to this limit depends on a number of factors,
mainly the number of files, the lengths of paths and other metadata stored for files.
This is shown as \fIutilization of maximum supported archive size\fP\&.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B NAME
specify the archive name
.B REPOSITORY_OR_ARCHIVE
repository or archive to display information about
.UNINDENT
.SS options
.INDENT 0.0
@ -64,55 +68,87 @@ format output as JSON
.SS Archive filters
.INDENT 0.0
.TP
.BI \-a \ PATTERN\fR,\fB \ \-\-match\-archives \ PATTERN
only consider archives matching all patterns. See \(dqborg help match\-archives\(dq.
.BI \-P \ PREFIX\fR,\fB \ \-\-prefix \ PREFIX
only consider archive names starting with this prefix. (deprecated)
.TP
.BI \-a \ GLOB\fR,\fB \ \-\-glob\-archives \ GLOB
only consider archive names matching the glob. sh: rules apply (without actually using the sh: prefix), see \(dqborg help patterns\(dq.
.TP
.BI \-\-sort\-by \ KEYS
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id, tags, host, user; default is: timestamp
Comma\-separated list of sorting keys; valid keys are: timestamp, archive, name, id; default is: timestamp
.TP
.BI \-\-first \ N
consider the first N archives after other filters are applied
consider first N archives after other filters were applied
.TP
.BI \-\-last \ N
consider the last N archives after other filters are applied
.TP
.BI \-\-oldest \ TIMESPAN
consider archives between the oldest archive\(aqs timestamp and (oldest + TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newest \ TIMESPAN
consider archives between the newest archive\(aqs timestamp and (newest \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-older \ TIMESPAN
consider archives older than (now \- TIMESPAN), e.g., 7d or 12m.
.TP
.BI \-\-newer \ TIMESPAN
consider archives newer than (now \- TIMESPAN), e.g., 7d or 12m.
consider last N archives after other filters were applied
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ borg info aid:f7dea078
Archive name: source\-backup
Archive fingerprint: f7dea0788dfc026cc2be1c0f5b94beb4e4084eb3402fc40c38d8719b1bf2d943
.nf
.ft C
$ borg info /path/to/repo::2017\-06\-29T11:00\-srv
Archive name: 2017\-06\-29T11:00\-srv
Archive fingerprint: b2f1beac2bd553b34e06358afa45a3c1689320d39163890c5bbbd49125f00fe5
Comment:
Hostname: mba2020
Username: tw
Time (start): Sat, 2022\-06\-25 20:51:40
Time (end): Sat, 2022\-06\-25 20:51:40
Duration: 0.03 seconds
Command line: /usr/bin/borg \-r path/to/repo create source\-backup src
Utilization of maximum supported archive size: 0%
Number of files: 244
Original size: 13.80 MB
Deduplicated size: 531 B
.EE
Hostname: myhostname
Username: root
Time (start): Thu, 2017\-06\-29 11:03:07
Time (end): Thu, 2017\-06\-29 11:03:13
Duration: 5.66 seconds
Number of files: 17037
Command line: /usr/sbin/borg create /path/to/repo::2017\-06\-29T11:00\-srv /srv
Utilization of max. archive size: 0%
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
Original size Compressed size Deduplicated size
This archive: 12.53 GB 12.49 GB 1.62 kB
All archives: 121.82 TB 112.41 TB 215.42 GB
Unique chunks Total chunks
Chunk index: 1015213 626934122
$ borg info /path/to/repo \-\-last 1
Archive name: 2017\-06\-29T11:00\-srv
Archive fingerprint: b2f1beac2bd553b34e06358afa45a3c1689320d39163890c5bbbd49125f00fe5
Comment:
Hostname: myhostname
Username: root
Time (start): Thu, 2017\-06\-29 11:03:07
Time (end): Thu, 2017\-06\-29 11:03:13
Duration: 5.66 seconds
Number of files: 17037
Command line: /usr/sbin/borg create /path/to/repo::2017\-06\-29T11:00\-srv /srv
Utilization of max. archive size: 0%
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
Original size Compressed size Deduplicated size
This archive: 12.53 GB 12.49 GB 1.62 kB
All archives: 121.82 TB 112.41 TB 215.42 GB
Unique chunks Total chunks
Chunk index: 1015213 626934122
$ borg info /path/to/repo
Repository ID: d857ce5788c51272c61535062e89eac4e8ef5a884ffbe976e0af9d8765dedfa5
Location: /path/to/repo
Encrypted: Yes (repokey)
Cache: /root/.cache/borg/d857ce5788c51272c61535062e89eac4e8ef5a884ffbe976e0af9d8765dedfa5
Security dir: /root/.config/borg/security/d857ce5788c51272c61535062e89eac4e8ef5a884ffbe976e0af9d8765dedfa5
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
Original size Compressed size Deduplicated size
All archives: 121.82 TB 112.41 TB 215.42 GB
Unique chunks Total chunks
Chunk index: 1015213 626934122
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-list(1)\fP, \fIborg\-diff(1)\fP, \fIborg\-repo\-info(1)\fP
.SH Author
\fIborg\-common(1)\fP, \fIborg\-list(1)\fP, \fIborg\-diff(1)\fP
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

272
docs/man/borg-init.1 Normal file
View file

@ -0,0 +1,272 @@
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "BORG-INIT" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-init \- Initialize an empty repository
.SH SYNOPSIS
.sp
borg [common options] init [options] [REPOSITORY]
.SH DESCRIPTION
.sp
This command initializes an empty repository. A repository is a filesystem
directory containing the deduplicated data from zero or more archives.
.SS Encryption mode TLDR
.sp
The encryption mode can only be configured when creating a new repository \-
you can neither configure it on a per\-archive basis nor change the
encryption mode of an existing repository.
.sp
Use \fBrepokey\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
borg init \-\-encryption repokey /path/to/repo
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
Or \fBrepokey\-blake2\fP depending on which is faster on your client machines (see below):
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
borg init \-\-encryption repokey\-blake2 /path/to/repo
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
Borg will:
.INDENT 0.0
.IP 1. 3
Ask you to come up with a passphrase.
.IP 2. 3
Create a borg key (which contains 3 random secrets. See \fIkey_files\fP).
.IP 3. 3
Encrypt the key with your passphrase.
.IP 4. 3
Store the encrypted borg key inside the repository directory (in the repo config).
This is why it is essential to use a secure passphrase.
.IP 5. 3
Encrypt and sign your backups to prevent anyone from reading or forging them unless they
have the key and know the passphrase. Make sure to keep a backup of
your key \fBoutside\fP the repository \- do not lock yourself out by
\(dqleaving your keys inside your car\(dq (see \fIborg_key_export\fP).
For remote backups the encryption is done locally \- the remote machine
never sees your passphrase, your unencrypted key or your unencrypted files.
Chunking and id generation are also based on your key to improve
your privacy.
.IP 6. 3
Use the key when extracting files to decrypt them and to verify that the contents of
the backups have not been accidentally or maliciously altered.
.UNINDENT
.SS Picking a passphrase
.sp
Make sure you use a good passphrase. Not too short, not too simple. The real
encryption / decryption key is encrypted with / locked by your passphrase.
If an attacker gets your key, he can\(aqt unlock and use it without knowing the
passphrase.
.sp
Be careful with special or non\-ascii characters in your passphrase:
.INDENT 0.0
.IP \(bu 2
Borg processes the passphrase as unicode (and encodes it as utf\-8),
so it does not have problems dealing with even the strangest characters.
.IP \(bu 2
BUT: that does not necessarily apply to your OS / VM / keyboard configuration.
.UNINDENT
.sp
So better use a long passphrase made from simple ascii chars than one that
includes non\-ascii stuff or characters that are hard/impossible to enter on
a different keyboard layout.
.sp
You can change your passphrase for existing repos at any time, it won\(aqt affect
the encryption/decryption key or other secrets.
.SS More encryption modes
.sp
Only use \fB\-\-encryption none\fP if you are OK with anyone who has access to
your repository being able to read your backups and tamper with their
contents without you noticing.
.sp
If you want \(dqpassphrase and having\-the\-key\(dq security, use \fB\-\-encryption keyfile\fP\&.
The key will be stored in your home directory (in \fB~/.config/borg/keys\fP).
.sp
If you do \fBnot\fP want to encrypt the contents of your backups, but still
want to detect malicious tampering use \fB\-\-encryption authenticated\fP\&.
To normally work with \fBauthenticated\fP repos, you will need the passphrase, but
there is an emergency workaround, see \fBBORG_WORKAROUNDS=authenticated_no_key\fP docs.
.sp
If \fBBLAKE2b\fP is faster than \fBSHA\-256\fP on your hardware, use \fB\-\-encryption authenticated\-blake2\fP,
\fB\-\-encryption repokey\-blake2\fP or \fB\-\-encryption keyfile\-blake2\fP\&. Note: for remote backups
the hashing is done on your local machine.
.\" nanorst: inline-fill
.
.TS
center;
|l|l|l|l|.
_
T{
Hash/MAC
T} T{
Not encrypted
no auth
T} T{
Not encrypted,
but authenticated
T} T{
Encrypted (AEAD w/ AES)
and authenticated
T}
_
T{
SHA\-256
T} T{
none
T} T{
\fIauthenticated\fP
T} T{
repokey
keyfile
T}
_
T{
BLAKE2b
T} T{
n/a
T} T{
\fIauthenticated\-blake2\fP
T} T{
\fIrepokey\-blake2\fP
\fIkeyfile\-blake2\fP
T}
_
.TE
.\" nanorst: inline-replace
.
.sp
Modes \fImarked like this\fP in the above table are new in Borg 1.1 and are not
backwards\-compatible with Borg 1.0.x.
.sp
On modern Intel/AMD CPUs (except very cheap ones), AES is usually
hardware\-accelerated.
BLAKE2b is faster than SHA256 on Intel/AMD 64\-bit CPUs
(except AMD Ryzen and future CPUs with SHA extensions),
which makes \fIauthenticated\-blake2\fP faster than \fInone\fP and \fIauthenticated\fP\&.
.sp
On modern ARM CPUs, NEON provides hardware acceleration for SHA256 making it faster
than BLAKE2b\-256 there. NEON accelerates AES as well.
.sp
Hardware acceleration is always used automatically when available.
.sp
\fIrepokey\fP and \fIkeyfile\fP use AES\-CTR\-256 for encryption and HMAC\-SHA256 for
authentication in an encrypt\-then\-MAC (EtM) construction. The chunk ID hash
is HMAC\-SHA256 as well (with a separate key).
These modes are compatible with Borg 1.0.x.
.sp
\fIrepokey\-blake2\fP and \fIkeyfile\-blake2\fP are also authenticated encryption modes,
but use BLAKE2b\-256 instead of HMAC\-SHA256 for authentication. The chunk ID
hash is a keyed BLAKE2b\-256 hash.
These modes are new and \fInot\fP compatible with Borg 1.0.x.
.sp
\fIauthenticated\fP mode uses no encryption, but authenticates repository contents
through the same HMAC\-SHA256 hash as the \fIrepokey\fP and \fIkeyfile\fP modes (it uses it
as the chunk ID hash). The key is stored like \fIrepokey\fP\&.
This mode is new and \fInot\fP compatible with Borg 1.0.x.
.sp
\fIauthenticated\-blake2\fP is like \fIauthenticated\fP, but uses the keyed BLAKE2b\-256 hash
from the other blake2 modes.
This mode is new and \fInot\fP compatible with Borg 1.0.x.
.sp
\fInone\fP mode uses no encryption and no authentication. It uses SHA256 as chunk
ID hash. This mode is not recommended, you should rather consider using an authenticated
or authenticated/encrypted mode. This mode has possible denial\-of\-service issues
when running \fBborg create\fP on contents controlled by an attacker.
Use it only for new repositories where no encryption is wanted \fBand\fP when compatibility
with 1.0.x is important. If compatibility with 1.0.x is not important, use
\fIauthenticated\-blake2\fP or \fIauthenticated\fP instead.
This mode is compatible with Borg 1.0.x.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B REPOSITORY
repository to create
.UNINDENT
.SS options
.INDENT 0.0
.TP
.BI \-e \ MODE\fR,\fB \ \-\-encryption \ MODE
select encryption key mode \fB(required)\fP
.TP
.B \-\-append\-only
create an append\-only mode repository. Note that this only affects the low level structure of the repository, and running \fIdelete\fP or \fIprune\fP will still be allowed. See \fIappend_only_mode\fP in Additional Notes for more details.
.TP
.BI \-\-storage\-quota \ QUOTA
Set storage quota of the new repository (e.g. 5G, 1.5T). Default: no quota.
.TP
.B \-\-make\-parent\-dirs
create the parent directories of the repository directory, if they are missing.
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
# Local repository, repokey encryption, BLAKE2b (often faster, since Borg 1.1)
$ borg init \-\-encryption=repokey\-blake2 /path/to/repo
# Local repository (no encryption)
$ borg init \-\-encryption=none /path/to/repo
# Remote repository (accesses a remote borg via ssh)
# repokey: stores the (encrypted) key into <REPO_DIR>/config
$ borg init \-\-encryption=repokey\-blake2 user@hostname:backup
# Remote repository (accesses a remote borg via ssh)
# keyfile: stores the (encrypted) key into ~/.config/borg/keys/
$ borg init \-\-encryption=keyfile user@hostname:backup
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-create(1)\fP, \fIborg\-delete(1)\fP, \fIborg\-check(1)\fP, \fIborg\-list(1)\fP, \fIborg\-key\-import(1)\fP, \fIborg\-key\-export(1)\fP, \fIborg\-key\-change\-passphrase(1)\fP
.SH AUTHOR
The Borg Collective
.\" Generated by docutils manpage writer.
.

View file

@ -1,66 +0,0 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key-add" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key-add \- Add a new borg key (protected by an independent passphrase) to the repository.
.SH SYNOPSIS
.sp
borg [common options] key add [options]
.SH DESCRIPTION
.sp
A repository can be protected by more than one borg key. Each borg key contains the
same secret key material, but is protected by an independent (potentially different)
passphrase, and any of them can be used to unlock the same repository. This is useful
e.g. to give individual users their own passphrase while keeping a separate
admin/recovery passphrase.
.sp
This command adds an additional borg key. It does not re\-encrypt any repository data
and does not change the existing borg keys. The new passphrase is read from
\fBBORG_NEW_PASSPHRASE\fP or queried interactively.
.sp
Each borg key has a label. The first borg key, created at repository creation time, has
the reserved label \fBadmin\fP and is protected from deletion. Additionally added borg
keys require a unique, user\-defined \fB\-\-label\fP\&.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS options
.INDENT 0.0
.TP
.BI \-\-label \ LABEL
label for the new borg key (must be unique)
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
The Borg Collective
.\" End of generated man page.

View file

@ -1,91 +0,0 @@
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "BORG-KEY-CHANGE-ALGORITHM" 1 "2022-06-26" "" "borg backup tool"
.SH NAME
borg-key-change-algorithm \- Change repository key algorithm
.SH SYNOPSIS
.sp
borg [common options] key change\-algorithm [options] ALGORITHM
.SH DESCRIPTION
.sp
Change the algorithm we use to encrypt and authenticate the borg key.
.sp
Important: In a \fIrepokey\fP mode (e.g. repokey\-blake2) all users share the same key.
In this mode upgrading to \fIargon2\fP will make it impossible to access the repo for users who use an old version of borg.
We recommend upgrading to the latest stable version.
.sp
Important: In a \fIkeyfile\fP mode (e.g. keyfile\-blake2) each user has their own key (in \fB~/.config/borg/keys\fP).
In this mode this command will only change the key used by the current user.
If you want to upgrade to \fIargon2\fP to strengthen security, you will have to upgrade each user\(aqs key individually.
.sp
Your repository is encrypted and authenticated with a key that is randomly generated by \fBborg init\fP\&.
The key is encrypted and authenticated with your passphrase.
.sp
We currently support two choices:
.INDENT 0.0
.IP 1. 3
argon2 \- recommended. This algorithm is used by default when initialising a new repository.
The key encryption key is derived from your passphrase via argon2\-id.
Argon2 is considered more modern and secure than pbkdf2.
.IP 2. 3
pbkdf2 \- the legacy algorithm. Use this if you want to access your repo via old versions of borg.
The key encryption key is derived from your passphrase via PBKDF2\-HMAC\-SHA256.
.UNINDENT
.sp
Examples:
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
# Upgrade an existing key to argon2
borg key change\-algorithm /path/to/repo argon2
# Downgrade to pbkdf2 \- use this if upgrading borg is not an option
borg key change\-algorithm /path/to/repo pbkdf2
.ft P
.fi
.UNINDENT
.UNINDENT
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B ALGORITHM
select key algorithm
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH AUTHOR
The Borg Collective
.\" Generated by docutils manpage writer.
.

View file

@ -1,71 +0,0 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key-change-location" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key-change-location \- Changes the location of the borg key used to unlock this repository.
.SH SYNOPSIS
.sp
borg [common options] key change\-location [options] KEY_LOCATION
.SH DESCRIPTION
.sp
Change the location of a Borg key. The key can be stored at different locations:
.INDENT 0.0
.IP \(bu 2
keyfile: locally, usually in the home directory
.IP \(bu 2
repokey: inside the repository
.UNINDENT
.sp
Please note:
.sp
This command does NOT change the crypto algorithms, just the key location,
thus you must ONLY give the key location (keyfile or repokey).
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.INDENT 0.0
.TP
.B KEY_LOCATION
select key location
.UNINDENT
.SS options
.INDENT 0.0
.TP
.B \-\-keep
keep the key also at the current location (default: remove it)
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
The Borg Collective
.\" End of generated man page.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,12 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key-change-passphrase" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key-change-passphrase \- Changes the repository key file passphrase.
.TH "BORG-KEY-CHANGE-PASSPHRASE" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-key-change-passphrase \- Change repository key file passphrase
.SH SYNOPSIS
.sp
borg [common options] key change\-passphrase [options]
borg [common options] key change\-passphrase [options] [REPOSITORY]
.SH DESCRIPTION
.sp
The key files used for repository encryption are optionally passphrase
@ -46,13 +45,17 @@ does not protect future (nor past) backups to the same repository.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.sp
REPOSITORY
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.nf
.ft C
# Create a key file protected repository
$ borg repo\-create \-\-encryption=aes\-ocb \-\-key\-location=keyfile \-v
$ borg init \-\-encryption=keyfile \-v /path/to/repo
Initializing repository at \(dq/path/to/repo\(dq
Enter new passphrase:
Enter same passphrase again:
@ -64,34 +67,19 @@ Archives: 0, w/ cached Idx: 0, w/ outdated Idx: 0, w/o cached Idx: 0.
Done.
# Change key file passphrase
$ borg key change\-passphrase \-v
$ borg key change\-passphrase \-v /path/to/repo
Enter passphrase for key /root/.config/borg/keys/mnt_backup:
Enter new passphrase:
Enter same passphrase again:
Remember your passphrase. Your data will be inaccessible without it.
Key updated
.EE
.UNINDENT
.UNINDENT
.sp
\fBNote:\fP
.INDENT 0.0
.INDENT 3.5
The key file paths shown above are the defaults for Linux (\fB~/.config/borg/keys/\fP).
On macOS, key files are stored in \fB~/Library/Application Support/borg/keys/\fP\&.
On Windows, they are stored in \fBC:\eUsers\e<user>\eAppData\eRoaming\eborg\ekeys\e\fP\&.
See \fIenv_vars\fP for details.
.UNINDENT
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Import a previously\-exported key into the specified
# key file (creating or overwriting the output key)
# (keyfile repositories only)
$ BORG_KEY_FILE=/path/to/output\-key borg key import /path/to/exported
.EE
$ BORG_KEY_FILE=/path/to/output\-key borg key import /path/to/repo /path/to/exported
.ft P
.fi
.UNINDENT
.UNINDENT
.sp
@ -99,17 +87,20 @@ Fully automated using environment variables:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ BORG_NEW_PASSPHRASE=old borg repo\-create \-\-encryption=aes\-ocb
.nf
.ft C
$ BORG_NEW_PASSPHRASE=old borg init \-e=repokey repo
# now \(dqold\(dq is the current passphrase.
$ BORG_PASSPHRASE=old BORG_NEW_PASSPHRASE=new borg key change\-passphrase
$ BORG_PASSPHRASE=old BORG_NEW_PASSPHRASE=new borg key change\-passphrase repo
# now \(dqnew\(dq is the current passphrase.
.EE
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,51 +27,59 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key-export" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key-export \- Exports a borg key of the repository for backup.
.TH "BORG-KEY-EXPORT" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-key-export \- Export the repository key for backup
.SH SYNOPSIS
.sp
borg [common options] key export [options] [PATH]
borg [common options] key export [options] [REPOSITORY] [PATH]
.SH DESCRIPTION
.sp
This command backs up the borg key.
.sp
If repository encryption is used, the repository is inaccessible
without the borg key (and the passphrase that protects the borg key).
If a repository is not encrypted, but authenticated, the borg key is
still needed to access the repository normally.
.sp
For repositories using \fBkeyfile\fP encryption the key is kept locally
on the system that is capable of doing backups. To guard against loss
or corruption of this key, the key needs to be backed up independently
of the main data backup.
.sp
For repositories using \fBrepokey\fP encryption or \fBauthenticated\fP mode
the key is kept in the repository. A backup is thus not strictly needed,
but guards against the repository becoming inaccessible if the key is
corrupted or lost.
.sp
without the key. This command allows one to backup this essential key.
Note that the backup produced does not include the passphrase itself
(i.e. the exported key stays encrypted). In order to regain access to a
repository, one needs both the exported key and the original passphrase.
Keep the exported key and the passphrase at safe places.
.sp
A repository may have more than one borg key (each protected by its own
passphrase, see \fBborg key add\fP). Select which borg key to export with
\fB\-\-label\fP or \fB\-\-key\fP (its key id or a unique prefix, see
\fBborg key list\fP). If the repository has only a single borg key, no
selector is required.
.sp
There are three backup formats. The normal backup format is suitable for
digital storage as a file. The \fB\-\-paper\fP backup format is optimized
for printing and typing in while importing, with per line checks to
reduce problems with manual input. The \fB\-\-qr\-html\fP creates a printable
HTML template with a QR code and a copy of the \fB\-\-paper\fP\-formatted key.
.sp
For repositories using keyfile encryption the key is saved locally
on the system that is capable of doing backups. To guard against loss
of this key, the key needs to be backed up independently of the main
data backup.
.sp
For repositories using the repokey encryption the key is saved in the
repository in the config file. A backup is thus not strictly needed,
but guards against the repository becoming inaccessible if the file
is damaged for some reason.
.sp
Examples:
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
borg key export /path/to/repo > encrypted\-key\-backup
borg key export \-\-paper /path/to/repo > encrypted\-key\-backup.txt
borg key export \-\-qr\-html /path/to/repo > encrypted\-key\-backup.html
# Or pass the output file as an argument instead of redirecting stdout:
borg key export /path/to/repo encrypted\-key\-backup
borg key export \-\-paper /path/to/repo encrypted\-key\-backup.txt
borg key export \-\-qr\-html /path/to/repo encrypted\-key\-backup.html
.ft P
.fi
.UNINDENT
.UNINDENT
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.sp
REPOSITORY
.INDENT 0.0
.TP
.B PATH
@ -81,36 +88,16 @@ where to store the backup
.SS options
.INDENT 0.0
.TP
.BI \-\-label \ LABEL
export the borg key with this label
.TP
.BI \-\-key \ ID
export the borg key with this id (or unique id prefix)
.TP
.B \-\-paper
Create an export suitable for printing and later type\-in
.TP
.B \-\-qr\-html
Create an HTML file suitable for printing and later type\-in or QR scan
.UNINDENT
.SH EXAMPLES
.INDENT 0.0
.INDENT 3.5
.sp
.EX
borg key export > encrypted\-key\-backup
borg key export \-\-paper > encrypted\-key\-backup.txt
borg key export \-\-qr\-html > encrypted\-key\-backup.html
# Or pass the output file as an argument instead of redirecting stdout:
borg key export encrypted\-key\-backup
borg key export \-\-paper encrypted\-key\-backup.txt
borg key export \-\-qr\-html encrypted\-key\-backup.html
.EE
.UNINDENT
Create an html file suitable for printing and later type\-in or qr scan
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-key\-import(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,12 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key-import" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key-import \- Imports the repository key from backup.
.TH "BORG-KEY-IMPORT" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-key-import \- Import the repository key from backup
.SH SYNOPSIS
.sp
borg [common options] key import [options] [PATH]
borg [common options] key import [options] [REPOSITORY] [PATH]
.SH DESCRIPTION
.sp
This command restores a key previously backed up with the export command.
@ -54,6 +53,8 @@ key import\fP creates a new key file in \fB$BORG_KEYS_DIR\fP\&.
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS arguments
.sp
REPOSITORY
.INDENT 0.0
.TP
.B PATH
@ -64,13 +65,11 @@ path to the backup (\(aq\-\(aq to read from stdin)
.TP
.B \-\-paper
interactively import from a backup done with \fB\-\-paper\fP
.TP
.BI \-\-key\-location \ LOCATION
where to store the imported key: \(aqrepokey\(aq (in the repository, default) or \(aqkeyfile\(aq (in the local keys directory)
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-key\-export(1)\fP
.SH Author
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

View file

@ -1,50 +0,0 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key-list" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key-list \- List the borg keys of the repository.
.SH SYNOPSIS
.sp
borg [common options] key list [options]
.SH DESCRIPTION
.sp
List the borg keys of the repository, showing each borg key\(aqs id, mode (\fBrepokey\fP or
\fBkeyfile\fP), label and key derivation/encryption algorithm. The borg key used to
unlock the repository in this invocation is marked with \fB*\fP\&.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
The Borg Collective
.\" End of generated man page.

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "BORG-KEY-MIGRATE-TO-REPOKEY" 1 "2022-02-19" "" "borg backup tool"
.TH "BORG-KEY-MIGRATE-TO-REPOKEY" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-key-migrate-to-repokey \- Migrate passphrase -> repokey
.SH SYNOPSIS

View file

@ -1,67 +0,0 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key-remove" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key-remove \- Remove a borg key from the repository.
.SH SYNOPSIS
.sp
borg [common options] key remove [options]
.SH DESCRIPTION
.sp
Remove a borg key from the repository.
.sp
The borg key to remove is selected by exactly one of: \fB\-\-label\fP (its label),
\fB\-\-key\fP (its key id or a unique prefix, see \fBborg key list\fP), or
\fB\-\-passphrase\fP (remove the borg key that was used to unlock the repository now).
.sp
The \fBadmin\fP borg key is protected and cannot be removed, and the last remaining
borg key of a repository cannot be removed either.
.SH OPTIONS
.sp
See \fIborg\-common(1)\fP for common options of Borg commands.
.SS options
.INDENT 0.0
.TP
.BI \-\-label \ LABEL
remove the borg key with this label
.TP
.BI \-\-key \ ID
remove the borg key with this id (or unique id prefix)
.TP
.B \-\-passphrase
remove the borg key that was used to unlock the repository
.UNINDENT
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP
.SH Author
The Borg Collective
.\" End of generated man page.

View file

@ -1,5 +1,4 @@
.\" Man page generated from reStructuredText
.\" by the Docutils 0.22.4 manpage writer.
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
@ -28,23 +27,21 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "borg-key" "1" "2026-06-16" "" "borg backup tool"
.SH Name
borg-key \- Manage the keyfile or repokey of a repository
.TH "BORG-KEY" 1 "2023-12-02" "" "borg backup tool"
.SH NAME
borg-key \- Manage a keyfile or repokey of a repository
.SH SYNOPSIS
.nf
borg [common options] key export ...
borg [common options] key import ...
borg [common options] key change\-passphrase ...
borg [common options] key add ...
borg [common options] key remove ...
borg [common options] key list ...
borg [common options] key change\-location ...
borg [common options] key migrate\-to\-repokey ...
.fi
.sp
.SH SEE ALSO
.sp
\fIborg\-common(1)\fP, \fIborg\-key\-export(1)\fP, \fIborg\-key\-import(1)\fP, \fIborg\-key\-change\-passphrase(1)\fP, \fIborg\-key\-add(1)\fP, \fIborg\-key\-remove(1)\fP, \fIborg\-key\-list(1)\fP, \fIborg\-key\-change\-location(1)\fP
.SH Author
\fIborg\-common(1)\fP, \fIborg\-key\-export(1)\fP, \fIborg\-key\-import(1)\fP, \fIborg\-key\-change\-passphrase(1)\fP, \fIborg\-key\-migrate\-to\-repokey(1)\fP
.SH AUTHOR
The Borg Collective
.\" End of generated man page.
.\" Generated by docutils manpage writer.
.

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