diff -Nru borgbackup2-2.0.0b18/CHANGES.rst borgbackup2-2.0.0b19/CHANGES.rst --- borgbackup2-2.0.0b18/CHANGES.rst 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/CHANGES.rst 2025-08-02 13:55:43.000000000 +0200 @@ -144,7 +144,7 @@ Change Log 2.x ============== -Version 2.0.0b18 (2025-06-19) +Version 2.0.0b19 (2025-07-02) ----------------------------- Please note: @@ -154,6 +154,28 @@ For upgrade and compatibility hints, please also read the section "Upgrade Notes" above. +Fixes: + +- reader: fix corruption issue "forgetting" all-zero bytestrings, #8963 +- import-tar: normalize the tarinfo name/linkname when used as hlm key. + also: when printing the path, use the already normalized item.path. +- import-tar: fix the dotslash issue, add test + +New features: + +- create --files-changed=MODE option, #8958. + control how borg detects whether a file has changed while it was backed up, + valid modes are ctime (default), mtime (2nd best) or disabled (not recommended). + +Other changes: + +- to_key_filename: raise length limit to 120, #8966. + This works around a test failure on systems with deep build directories. + + +Version 2.0.0b18 (2025-06-19) +----------------------------- + New features: - experimental new "buzhash64" chunker (later, after testing, this shall become diff -Nru borgbackup2-2.0.0b18/debian/changelog borgbackup2-2.0.0b19/debian/changelog --- borgbackup2-2.0.0b18/debian/changelog 2025-06-23 10:34:09.000000000 +0200 +++ borgbackup2-2.0.0b19/debian/changelog 2025-08-04 18:11:35.000000000 +0200 @@ -1,3 +1,26 @@ +borgbackup2 (2.0.0b19-1) unstable; urgency=medium + + * New upstream version 2.0.0b19 + - fixes a corruption bug: https://github.com/borgbackup/borg/issues/8963 + + -- Gianfranco Costamagna Mon, 04 Aug 2025 18:11:35 +0200 + +borgbackup2 (2.0.0b18-3) unstable; urgency=medium + + [ Simon Chopin ] + * fix running unit tests in autopkgtests (Closes: #1110195, LP: #2118916) + + [ Gianfranco Costamagna ] + * Team upload + + -- Gianfranco Costamagna Fri, 01 Aug 2025 13:58:15 +0200 + +borgbackup2 (2.0.0b18-2) unstable; urgency=medium + + * Merge borgbackup 1.4.1-4 + + -- Gianfranco Costamagna Fri, 18 Jul 2025 12:45:37 +0200 + borgbackup2 (2.0.0b18-1) unstable; urgency=medium * New upstream version 2.0.0b18 @@ -336,6 +359,114 @@ -- Helmut Grohne Mon, 16 Jan 2023 09:32:00 +0100 +borgbackup (1.4.1-4) unstable; urgency=medium + + * Team upload. + + [ Helmut Grohne ] + * Split the unit autopkgtest into a fuse one and one without. + + [ Helmut Grohne and Nicholas D Steeves] + * Symlink debian/tests/unit-nofuse -> unit. This autopkgtest leverages + upstream's support to conditionally skip tests when dependencies are + missing. Compare the delta between unit and unit-nofuse's Depends to + learn what may be required to create -nofuse autopkgtest variants for + other packages. + + -- Nicholas D Steeves Tue, 08 Jul 2025 19:21:34 -0400 + +borgbackup (1.4.1-3) unstable; urgency=medium + + * Team upload. + + [ Nicholas D Steeves ] + * Update debian/NEWS: Upstream introduced less alarming and easier to + follow migration instructions in 1.2.8, and this is their officially + supported procedure. + * Git shortlog of Debian-facing upstream changes between upstream's 1.4.0 and + 1.4.1, (for trixie unblock): + + ecf2dfa17 build_usage / build_man [docs] + 1bed2155d update CHANGES + 3880c7e12 implement padme chunk size obfuscation (SPEC 250), fixes #8705 + 49fa6c476 update CHANGES + aba21ee18 freebsd: fix nfs4 acl processing, fixes #8756 + dddb6b155 fix remote repository exception handling / exit codes, fixes #8631 + 0b6150c74 Fix paper key import error message + 11ac0cdc6 docs: theme fixes + 46c44b9d9 docs: fix template to support search result preview + ecd797611 docs: add layout.html template from guzzle_sphinx_theme 0.7.11 + 31784547b work around sudden failure of sphinx ini lexer + 8b1840640 Clearer language + a21f08ac6 update CHANGES + 8ffd26300 set archive timestamps in local timezone + 3a932c587 Revert "Fix hourly prune test failure due to non-full-hour + timezone" + 570c97eb1 run prune tests in specific full hour timezone + 7cf831609 quickfix to disallow running borg with assertions switched off + 8e6dc52a8 Fix #8522: Add {unixtime} placeholders (1.4-maint) (#8675) + a1a028cef FAQ: Why are backups slow on a Linux server that is a member of a + windows domain? + fc0c799db docs: modify docs for automated backup to append to SYSTEMD_WANTS + rather than overwrite + 5634e49fe docs: fix udev rule priority in automated-local.rst + 15ec434b5 docs: clarify requirements when using command line options with + special characters within a shell #8628 + 54e526cfc fix security policy: 1.4.x is security supported + 21c3b8688 it's 2025 + 301aacecd docs: remove 3rd_party licenses + cda01c7ba docs: add FAQ entry about pure-python msgpack warning, fixes #8323 + 16e4b3087 binary readme: first check faq and existing issues + d3b23b0e6 update CHANGES + 2dfb5d9a0 use Cython 3.0.11 + 7d9028a22 mount docs: apply jdchristensen's suggestion, better phrasing. + f0bd01b98 FAQ: Why is backing up an unmodified FAT filesystem slow on Linux? + 88ce37b73 update CHANGES + a6dc8c52d check: more consistent messaging considering --repair, fixes #8533 + 69151c7a1 support and test on Python 3.13 + 4f794bbee config: reject additional_free_space < 10M, fixes #6066 + f0564036e yes: deal with UnicodeDecodeError in input(), fixes #6984 + 09745d22f compact: support --dry-run (do nothing), fixes #8300 + e74c91285 config: fix acceptance of storage_quota 0, fixes #8499 + 095b43ba3 docs: update install docs, nothing bundled anymore! fixes #8342. + 66e92636d Clarify excluded and included flags for dry-run in borg the docs + 8fe9c5ed6 docs: Small changes regarding compression + 05837fbeb docs/FAQ: Clean up entries regarding SSH settings + 2230932c0 docs: borg/borgfs detects internally under which name it was + invoked, fixes #8207 + cbbfc35db docs: mount: document on-demand loading, perf tips, fixes #7173 + cf472302d docs: better link modern return codes, fixes #8370 + 272033121 Do not assert on diff if hard link sources are not found due to + exclusions. + 2c1862007 fix WORKAROUNDS=authenticated_no_key support for archive TAM + authentication, fixes #8400 + 4f110f8bd Update repository URLs in docs to use new syntax Fixes #8361 + 81cb1cdc5 Add quarterly pruning strategy. (#8337) + 938e144f8 Ensure that 0B changes are hidden from text diffs too. + f7673e3f0 Add test to make sure 0-added,0-removed modified changes aren't in + JSON output. + 6e9857b3e Remove 0-added,0-removed modified entries from JSON output. + 54c902474 docs: align /etc/backups path in all references + adf2d8c04 remove outdated comment, fixes #4240 + 85d7bdd75 improve borg check --repair healing tests, see #8302 + 924952fcd Fix backwards compatibility of old chunks.archive.d file behavior + f3c1444a4 Update docs for BORG_USE_CHUNKS_ARCHIVE + 0575f8758 Add BORG_USE_CHUNKS_ARCHIVE option + 0bd41ba65 Automatic rebuild cache on exception, fixes #5213 (#8257) + b379202be docs: fix typo (backport #8272) + + [ Lee Garrett ] + * Add myself to Uploaders. + * Add missing end of sentence punctuation in the long description. + * Update metadata (Vcs-Git/gbp.conf) to point to trixie branch. + * Add unit tests to autopkgtests. + + [ Nicholas D Steeves ] + * Additionally enable autopkgtest-pkg-python (see Debian Python Team for why + one should use both). + + -- Nicholas D Steeves Sat, 28 Jun 2025 14:18:42 -0400 + borgbackup (1.4.1-2) unstable; urgency=medium * Add fix from borgbackup2 diff -Nru borgbackup2-2.0.0b18/debian/control borgbackup2-2.0.0b19/debian/control --- borgbackup2-2.0.0b18/debian/control 2025-05-30 18:26:31.000000000 +0200 +++ borgbackup2-2.0.0b19/debian/control 2025-07-18 12:42:08.000000000 +0200 @@ -39,6 +39,8 @@ Homepage: https://borgbackup.github.io/borgbackup/ Vcs-Git: https://salsa.debian.org/debian/borgbackup2.git Vcs-Browser: https://salsa.debian.org/debian/borgbackup2 +Testsuite: autopkgtest-pkg-python +# functional unit tests have been configured in debian/tests/unit Package: borgbackup2 Architecture: any @@ -115,4 +117,4 @@ possible to restrict the ssh key to "borg serve" using the authorized_keys command= clause. . - This is the documentation package + This is the documentation package. diff -Nru borgbackup2-2.0.0b18/debian/patches/0008-tests-tweak-some-unit-tests-when-using-the-installed.patch borgbackup2-2.0.0b19/debian/patches/0008-tests-tweak-some-unit-tests-when-using-the-installed.patch --- borgbackup2-2.0.0b18/debian/patches/0008-tests-tweak-some-unit-tests-when-using-the-installed.patch 1970-01-01 01:00:00.000000000 +0100 +++ borgbackup2-2.0.0b19/debian/patches/0008-tests-tweak-some-unit-tests-when-using-the-installed.patch 2025-08-01 20:58:32.000000000 +0200 @@ -0,0 +1,61 @@ +From: Simon Chopin +Date: Thu, 31 Jul 2025 18:20:16 +0200 +Subject: tests: tweak some unit tests when using the installed testsuite + +In autopkgtests we want to test the installed code, but a couple of unit +tests assume (not unreasonably) that they're run from the source repo. + +We introduce a new environment variable that allows us to tweak a few +tests, either disabling them out-right or changing some of the paths to +point to the installed files. + +This is *very* Debian-specific, no need to push upstream. + +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/borgbackup2/+bug/2118916 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1110195 +Forwarded: not-needed +--- + src/borg/testsuite/shell_completions_test.py | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/borg/testsuite/shell_completions_test.py b/src/borg/testsuite/shell_completions_test.py +index 3ec3e71..46fa326 100644 +--- a/src/borg/testsuite/shell_completions_test.py ++++ b/src/borg/testsuite/shell_completions_test.py +@@ -1,14 +1,19 @@ + import subprocess ++import os + from pathlib import Path + + import pytest + ++INSTALLED = os.environ.get("TEST_INSTALLED_CODE") == "1" + SHELL_COMPLETIONS_DIR = Path(__file__).parent / ".." / ".." / ".." / ".." / ".." / "scripts" / "shell_completions" + + + def test_bash_completion_is_valid(): + """Test that the bash completion file is valid bash syntax.""" +- bash_completion_file = SHELL_COMPLETIONS_DIR / "bash" / "borg" ++ if INSTALLED: ++ bash_completion_file = Path("/usr/share/bash-completion/completions/borg2") ++ else: ++ bash_completion_file = SHELL_COMPLETIONS_DIR / "bash" / "borg" + assert bash_completion_file.is_file() + + # Check if bash is available +@@ -22,6 +27,7 @@ def test_bash_completion_is_valid(): + assert result.returncode == 0, f"Bash completion file has syntax errors: {result.stderr.decode()}" + + ++@pytest.mark.skipif(INSTALLED, reason="not installed in Debian") + def test_fish_completion_is_valid(): + """Test that the fish completion file is valid fish syntax.""" + fish_completion_file = SHELL_COMPLETIONS_DIR / "fish" / "borg.fish" +@@ -38,6 +44,7 @@ def test_fish_completion_is_valid(): + assert result.returncode == 0, f"Fish completion file has syntax errors: {result.stderr.decode()}" + + ++@pytest.mark.skipif(INSTALLED, reason="not installed in Debian") + def test_zsh_completion_is_valid(): + """Test that the zsh completion file is valid zsh syntax.""" + zsh_completion_file = SHELL_COMPLETIONS_DIR / "zsh" / "_borg" diff -Nru borgbackup2-2.0.0b18/debian/patches/series borgbackup2-2.0.0b19/debian/patches/series --- borgbackup2-2.0.0b18/debian/patches/series 2025-06-23 10:34:09.000000000 +0200 +++ borgbackup2-2.0.0b19/debian/patches/series 2025-08-01 20:58:32.000000000 +0200 @@ -5,3 +5,4 @@ explicit_version.patch manifest-data-files.patch fix-testsuite-shell.patch +0008-tests-tweak-some-unit-tests-when-using-the-installed.patch diff -Nru borgbackup2-2.0.0b18/debian/tests/control borgbackup2-2.0.0b19/debian/tests/control --- borgbackup2-2.0.0b18/debian/tests/control 2025-05-30 18:26:31.000000000 +0200 +++ borgbackup2-2.0.0b19/debian/tests/control 2025-07-18 12:42:32.000000000 +0200 @@ -1,3 +1,37 @@ +Tests: unit +Depends: + @, + coreutils, + e2fsprogs, + fakeroot, + fuse3, + python3-llfuse, + python3-pyfuse3, + python3-pytest, + python3-pytest-benchmark, + python3-pytest-cov, + python3-pytest-xdist, + xattr, +Restrictions: + allow-stderr, + isolation-machine, + needs-sudo + +Tests: unit-nofuse +Depends: + @, + coreutils, + e2fsprogs, + fakeroot, + python3-pytest, + python3-pytest-benchmark, + python3-pytest-cov, + python3-pytest-xdist, + xattr, +Restrictions: + allow-stderr, + needs-sudo + Tests: simplesession Depends: @, @recommends@ Restrictions: isolation-machine, allow-stderr diff -Nru borgbackup2-2.0.0b18/debian/tests/unit borgbackup2-2.0.0b19/debian/tests/unit --- borgbackup2-2.0.0b18/debian/tests/unit 1970-01-01 01:00:00.000000000 +0100 +++ borgbackup2-2.0.0b19/debian/tests/unit 2025-08-01 20:58:32.000000000 +0200 @@ -0,0 +1,36 @@ +#!/usr/bin/sh + +set -euo pipefail + +cleanup() { + # preserve exit code + exit_code="$?" + echo 'Remove user/group "übel" again' + sudo groupdel übel || /usr/bin/true + sudo userdel übel || /usr/bin/true + exit "${exit_code}" +} + +trap cleanup EXIT + +echo "Creating user 'übel', used in src/borg/testsuite/platform.py::test_non_ascii_acl" +GROUPENTRY='übel:x:666:' +# gross hack because groupadd can't handle bad names +grep "${GROUPENTRY}" /etc/group || sudo sh -c "echo ${GROUPENTRY} >> /etc/group" +id übel || sudo useradd --uid 666 --gid 666 --badname übel + +echo "Create borg.exe symlink for many tests in src/borg/testsuite/archiver.py" +mkdir bin +ln -s /usr/bin/borg ./bin/borg.exe +PATH="$(pwd)/bin/:${PATH}" +export PATH +echo export PATH="$PATH" >> ~/.profile + +echo "Running the unit test suite ..." + +TEST_INSTALLED_CODE=1 \ +PYTHONPATH=/usr/lib/borgbackup2 \ +pytest \ + -n auto -rs \ + --benchmark-skip \ + --pyargs borg.testsuite diff -Nru borgbackup2-2.0.0b18/debian/tests/unit-nofuse borgbackup2-2.0.0b19/debian/tests/unit-nofuse --- borgbackup2-2.0.0b18/debian/tests/unit-nofuse 1970-01-01 01:00:00.000000000 +0100 +++ borgbackup2-2.0.0b19/debian/tests/unit-nofuse 2025-08-01 20:58:32.000000000 +0200 @@ -0,0 +1,36 @@ +#!/usr/bin/sh + +set -euo pipefail + +cleanup() { + # preserve exit code + exit_code="$?" + echo 'Remove user/group "übel" again' + sudo groupdel übel || /usr/bin/true + sudo userdel übel || /usr/bin/true + exit "${exit_code}" +} + +trap cleanup EXIT + +echo "Creating user 'übel', used in src/borg/testsuite/platform.py::test_non_ascii_acl" +GROUPENTRY='übel:x:666:' +# gross hack because groupadd can't handle bad names +grep "${GROUPENTRY}" /etc/group || sudo sh -c "echo ${GROUPENTRY} >> /etc/group" +id übel || sudo useradd --uid 666 --gid 666 --badname übel + +echo "Create borg.exe symlink for many tests in src/borg/testsuite/archiver.py" +mkdir bin +ln -s /usr/bin/borg ./bin/borg.exe +PATH="$(pwd)/bin/:${PATH}" +export PATH +echo export PATH="$PATH" >> ~/.profile + +echo "Running the unit test suite ..." + +TEST_INSTALLED_CODE=1 \ +PYTHONPATH=/usr/lib/borgbackup2 \ +pytest \ + -n auto -rs \ + --benchmark-skip \ + --pyargs borg.testsuite diff -Nru borgbackup2-2.0.0b18/docs/changes.rst borgbackup2-2.0.0b19/docs/changes.rst --- borgbackup2-2.0.0b18/docs/changes.rst 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/changes.rst 2025-08-02 13:55:43.000000000 +0200 @@ -144,7 +144,7 @@ Change Log 2.x ============== -Version 2.0.0b18 (2025-06-19) +Version 2.0.0b19 (2025-07-02) ----------------------------- Please note: @@ -154,6 +154,28 @@ For upgrade and compatibility hints, please also read the section "Upgrade Notes" above. +Fixes: + +- reader: fix corruption issue "forgetting" all-zero bytestrings, #8963 +- import-tar: normalize the tarinfo name/linkname when used as hlm key. + also: when printing the path, use the already normalized item.path. +- import-tar: fix the dotslash issue, add test + +New features: + +- create --files-changed=MODE option, #8958. + control how borg detects whether a file has changed while it was backed up, + valid modes are ctime (default), mtime (2nd best) or disabled (not recommended). + +Other changes: + +- to_key_filename: raise length limit to 120, #8966. + This works around a test failure on systems with deep build directories. + + +Version 2.0.0b18 (2025-06-19) +----------------------------- + New features: - experimental new "buzhash64" chunker (later, after testing, this shall become diff -Nru borgbackup2-2.0.0b18/docs/man/borg.1 borgbackup2-2.0.0b19/docs/man/borg.1 --- borgbackup2-2.0.0b18/docs/man/borg.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg.1 2025-08-02 13:55:43.000000000 +0200 @@ -28,7 +28,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg \- deduplicating and encrypting backup tool .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-analyze.1 borgbackup2-2.0.0b19/docs/man/borg-analyze.1 --- borgbackup2-2.0.0b18/docs/man/borg-analyze.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-analyze.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-ANALYZE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-ANALYZE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-analyze \- Analyze archives .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-benchmark.1 borgbackup2-2.0.0b19/docs/man/borg-benchmark.1 --- borgbackup2-2.0.0b18/docs/man/borg-benchmark.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-benchmark.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-BENCHMARK" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-BENCHMARK" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-benchmark \- benchmark command .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-benchmark-cpu.1 borgbackup2-2.0.0b19/docs/man/borg-benchmark-cpu.1 --- borgbackup2-2.0.0b18/docs/man/borg-benchmark-cpu.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-benchmark-cpu.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-BENCHMARK-CPU" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-BENCHMARK-CPU" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-benchmark-cpu \- Benchmark CPU bound operations. .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-benchmark-crud.1 borgbackup2-2.0.0b19/docs/man/borg-benchmark-crud.1 --- borgbackup2-2.0.0b18/docs/man/borg-benchmark-crud.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-benchmark-crud.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-BENCHMARK-CRUD" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-BENCHMARK-CRUD" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-benchmark-crud \- Benchmark Create, Read, Update, Delete for archives. .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-break-lock.1 borgbackup2-2.0.0b19/docs/man/borg-break-lock.1 --- borgbackup2-2.0.0b18/docs/man/borg-break-lock.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-break-lock.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-BREAK-LOCK" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-BREAK-LOCK" "1" "2025-08-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 diff -Nru borgbackup2-2.0.0b18/docs/man/borg-check.1 borgbackup2-2.0.0b19/docs/man/borg-check.1 --- borgbackup2-2.0.0b18/docs/man/borg-check.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-check.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-CHECK" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-CHECK" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-check \- Check repository consistency .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-common.1 borgbackup2-2.0.0b19/docs/man/borg-common.1 --- borgbackup2-2.0.0b18/docs/man/borg-common.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-common.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-COMMON" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-COMMON" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-common \- Common options of Borg commands .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-compact.1 borgbackup2-2.0.0b19/docs/man/borg-compact.1 --- borgbackup2-2.0.0b18/docs/man/borg-compact.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-compact.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-COMPACT" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-COMPACT" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-compact \- Collect garbage in repository .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-compression.1 borgbackup2-2.0.0b19/docs/man/borg-compression.1 --- borgbackup2-2.0.0b18/docs/man/borg-compression.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-compression.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-COMPRESSION" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-COMPRESSION" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-compression \- Details regarding compression .SH DESCRIPTION diff -Nru borgbackup2-2.0.0b18/docs/man/borg-create.1 borgbackup2-2.0.0b19/docs/man/borg-create.1 --- borgbackup2-2.0.0b18/docs/man/borg-create.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-create.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-CREATE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-CREATE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-create \- Create new archive .SH SYNOPSIS @@ -106,6 +106,20 @@ 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): Use ctime to detect changes. This is the safest option. +.IP \(bu 2 +mtime: 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 +.UNINDENT .sp The mount points of filesystems or filesystem snapshots should be the same for every creation of a new archive to ensure fast operation. This is because the file cache that @@ -236,6 +250,9 @@ .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 +.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 diff -Nru borgbackup2-2.0.0b18/docs/man/borg-delete.1 borgbackup2-2.0.0b19/docs/man/borg-delete.1 --- borgbackup2-2.0.0b18/docs/man/borg-delete.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-delete.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-DELETE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-DELETE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-delete \- Delete archives .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-diff.1 borgbackup2-2.0.0b19/docs/man/borg-diff.1 --- borgbackup2-2.0.0b18/docs/man/borg-diff.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-diff.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-DIFF" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-DIFF" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-diff \- Diff contents of two archives .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-export-tar.1 borgbackup2-2.0.0b19/docs/man/borg-export-tar.1 --- borgbackup2-2.0.0b18/docs/man/borg-export-tar.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-export-tar.1 2025-08-02 13:55:43.000000000 +0200 @@ -28,7 +28,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-EXPORT-TAR" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-EXPORT-TAR" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-export-tar \- Export archive contents as a tarball .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-extract.1 borgbackup2-2.0.0b19/docs/man/borg-extract.1 --- borgbackup2-2.0.0b18/docs/man/borg-extract.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-extract.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-EXTRACT" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-EXTRACT" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-extract \- Extract archive contents .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borgfs.1 borgbackup2-2.0.0b19/docs/man/borgfs.1 --- borgbackup2-2.0.0b18/docs/man/borgfs.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borgfs.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORGFS" "1" "2025-06-18" "" "borg backup tool" +.TH "BORGFS" "1" "2025-08-02" "" "borg backup tool" .SH NAME borgfs \- Mount archive or an entire repository as a FUSE filesystem .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-import-tar.1 borgbackup2-2.0.0b19/docs/man/borg-import-tar.1 --- borgbackup2-2.0.0b18/docs/man/borg-import-tar.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-import-tar.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-IMPORT-TAR" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-IMPORT-TAR" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-import-tar \- Create a backup archive from a tarball .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-info.1 borgbackup2-2.0.0b19/docs/man/borg-info.1 --- borgbackup2-2.0.0b18/docs/man/borg-info.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-info.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-INFO" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-INFO" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-info \- Show archive details such as disk space used .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-key.1 borgbackup2-2.0.0b19/docs/man/borg-key.1 --- borgbackup2-2.0.0b18/docs/man/borg-key.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-key.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-KEY" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-KEY" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-key \- Manage a keyfile or repokey of a repository .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-key-change-location.1 borgbackup2-2.0.0b19/docs/man/borg-key-change-location.1 --- borgbackup2-2.0.0b18/docs/man/borg-key-change-location.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-key-change-location.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-KEY-CHANGE-LOCATION" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-KEY-CHANGE-LOCATION" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-key-change-location \- Change repository key location .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-key-change-passphrase.1 borgbackup2-2.0.0b19/docs/man/borg-key-change-passphrase.1 --- borgbackup2-2.0.0b18/docs/man/borg-key-change-passphrase.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-key-change-passphrase.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-KEY-CHANGE-PASSPHRASE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-KEY-CHANGE-PASSPHRASE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-key-change-passphrase \- Change repository key file passphrase .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-key-export.1 borgbackup2-2.0.0b19/docs/man/borg-key-export.1 --- borgbackup2-2.0.0b18/docs/man/borg-key-export.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-key-export.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-KEY-EXPORT" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-KEY-EXPORT" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-key-export \- Export the repository key for backup .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-key-import.1 borgbackup2-2.0.0b19/docs/man/borg-key-import.1 --- borgbackup2-2.0.0b18/docs/man/borg-key-import.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-key-import.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-KEY-IMPORT" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-KEY-IMPORT" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-key-import \- Import the repository key from backup .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-list.1 borgbackup2-2.0.0b19/docs/man/borg-list.1 --- borgbackup2-2.0.0b18/docs/man/borg-list.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-list.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-LIST" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-LIST" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-list \- List archive contents .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-match-archives.1 borgbackup2-2.0.0b19/docs/man/borg-match-archives.1 --- borgbackup2-2.0.0b18/docs/man/borg-match-archives.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-match-archives.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-MATCH-ARCHIVES" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-MATCH-ARCHIVES" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-match-archives \- Details regarding match-archives .SH DESCRIPTION diff -Nru borgbackup2-2.0.0b18/docs/man/borg-mount.1 borgbackup2-2.0.0b19/docs/man/borg-mount.1 --- borgbackup2-2.0.0b18/docs/man/borg-mount.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-mount.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-MOUNT" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-MOUNT" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-mount \- Mount archive or an entire repository as a FUSE filesystem .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-patterns.1 borgbackup2-2.0.0b19/docs/man/borg-patterns.1 --- borgbackup2-2.0.0b18/docs/man/borg-patterns.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-patterns.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-PATTERNS" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-PATTERNS" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-patterns \- Details regarding patterns .SH DESCRIPTION diff -Nru borgbackup2-2.0.0b18/docs/man/borg-placeholders.1 borgbackup2-2.0.0b19/docs/man/borg-placeholders.1 --- borgbackup2-2.0.0b18/docs/man/borg-placeholders.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-placeholders.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-PLACEHOLDERS" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-PLACEHOLDERS" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-placeholders \- Details regarding placeholders .SH DESCRIPTION diff -Nru borgbackup2-2.0.0b18/docs/man/borg-prune.1 borgbackup2-2.0.0b19/docs/man/borg-prune.1 --- borgbackup2-2.0.0b18/docs/man/borg-prune.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-prune.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-PRUNE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-PRUNE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-prune \- Prune repository archives according to specified rules .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-recreate.1 borgbackup2-2.0.0b19/docs/man/borg-recreate.1 --- borgbackup2-2.0.0b18/docs/man/borg-recreate.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-recreate.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-RECREATE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-RECREATE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-recreate \- Re-create archives .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-rename.1 borgbackup2-2.0.0b19/docs/man/borg-rename.1 --- borgbackup2-2.0.0b18/docs/man/borg-rename.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-rename.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-RENAME" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-RENAME" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-rename \- Rename an existing archive .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-repo-compress.1 borgbackup2-2.0.0b19/docs/man/borg-repo-compress.1 --- borgbackup2-2.0.0b18/docs/man/borg-repo-compress.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-repo-compress.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-REPO-COMPRESS" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-REPO-COMPRESS" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-repo-compress \- Repository (re-)compression .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-repo-create.1 borgbackup2-2.0.0b19/docs/man/borg-repo-create.1 --- borgbackup2-2.0.0b18/docs/man/borg-repo-create.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-repo-create.1 2025-08-02 13:55:43.000000000 +0200 @@ -28,7 +28,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-REPO-CREATE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-REPO-CREATE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-repo-create \- Create a new, empty repository .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-repo-delete.1 borgbackup2-2.0.0b19/docs/man/borg-repo-delete.1 --- borgbackup2-2.0.0b18/docs/man/borg-repo-delete.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-repo-delete.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-REPO-DELETE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-REPO-DELETE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-repo-delete \- Delete a repository .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-repo-info.1 borgbackup2-2.0.0b19/docs/man/borg-repo-info.1 --- borgbackup2-2.0.0b18/docs/man/borg-repo-info.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-repo-info.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-REPO-INFO" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-REPO-INFO" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-repo-info \- Show repository infos .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-repo-list.1 borgbackup2-2.0.0b19/docs/man/borg-repo-list.1 --- borgbackup2-2.0.0b18/docs/man/borg-repo-list.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-repo-list.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-REPO-LIST" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-REPO-LIST" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-repo-list \- List the archives contained in a repository .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-repo-space.1 borgbackup2-2.0.0b19/docs/man/borg-repo-space.1 --- borgbackup2-2.0.0b18/docs/man/borg-repo-space.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-repo-space.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-REPO-SPACE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-REPO-SPACE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-repo-space \- Manage reserved space in repository .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-serve.1 borgbackup2-2.0.0b19/docs/man/borg-serve.1 --- borgbackup2-2.0.0b18/docs/man/borg-serve.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-serve.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-SERVE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-SERVE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-serve \- Start in server mode. This command is usually not used manually. .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-tag.1 borgbackup2-2.0.0b19/docs/man/borg-tag.1 --- borgbackup2-2.0.0b18/docs/man/borg-tag.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-tag.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-TAG" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-TAG" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-tag \- Manage tags .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-transfer.1 borgbackup2-2.0.0b19/docs/man/borg-transfer.1 --- borgbackup2-2.0.0b18/docs/man/borg-transfer.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-transfer.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-TRANSFER" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-TRANSFER" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-transfer \- archives transfer from other repository, optionally upgrade data format .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-umount.1 borgbackup2-2.0.0b19/docs/man/borg-umount.1 --- borgbackup2-2.0.0b18/docs/man/borg-umount.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-umount.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-UMOUNT" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-UMOUNT" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-umount \- un-mount the FUSE filesystem .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-undelete.1 borgbackup2-2.0.0b19/docs/man/borg-undelete.1 --- borgbackup2-2.0.0b18/docs/man/borg-undelete.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-undelete.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-UNDELETE" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-UNDELETE" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-undelete \- Undelete archives .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-version.1 borgbackup2-2.0.0b19/docs/man/borg-version.1 --- borgbackup2-2.0.0b18/docs/man/borg-version.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-version.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-VERSION" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-VERSION" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-version \- Display the borg client / borg server version .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/man/borg-with-lock.1 borgbackup2-2.0.0b19/docs/man/borg-with-lock.1 --- borgbackup2-2.0.0b18/docs/man/borg-with-lock.1 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/man/borg-with-lock.1 2025-08-02 13:55:43.000000000 +0200 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "BORG-WITH-LOCK" "1" "2025-06-18" "" "borg backup tool" +.TH "BORG-WITH-LOCK" "1" "2025-08-02" "" "borg backup tool" .SH NAME borg-with-lock \- run a user specified command with the repository lock held .SH SYNOPSIS diff -Nru borgbackup2-2.0.0b18/docs/usage/create.rst.inc borgbackup2-2.0.0b19/docs/usage/create.rst.inc --- borgbackup2-2.0.0b18/docs/usage/create.rst.inc 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/docs/usage/create.rst.inc 2025-08-02 13:55:43.000000000 +0200 @@ -89,6 +89,8 @@ +-------------------------------------------------------+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | | ``--files-cache MODE`` | operate files cache in MODE. default: ctime,size,inode | +-------------------------------------------------------+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | | ``--files-changed MODE`` | specify how to detect if a file has changed during backup (ctime, mtime, disabled). default: ctime | + +-------------------------------------------------------+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | | ``--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. | +-------------------------------------------------------+---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | **Archive options** | @@ -158,6 +160,7 @@ --noxattrs do not read and store xattrs into archive --sparse detect sparse holes in input (supported only by fixed chunker) --files-cache MODE operate files cache in MODE. default: ctime,size,inode + --files-changed MODE specify how to detect if a file has changed during backup (ctime, mtime, disabled). default: ctime --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. @@ -232,6 +235,13 @@ 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. +The ``--files-changed`` option controls how Borg detects if a file has changed during backup: + - ctime (default): Use ctime to detect changes. This is the safest option. + - mtime: Use mtime to detect changes. + - disabled: Disable the "file has changed while we backed it up" detection completely. + This is not recommended unless you know what you're doing, as it could lead to + inconsistent backups if files change during the backup process. + The mount points of filesystems or filesystem snapshots should be the same for every creation of a new archive to ensure fast operation. This is because the file cache that is used to determine changed files quickly uses absolute filenames. diff -Nru borgbackup2-2.0.0b18/PKG-INFO borgbackup2-2.0.0b19/PKG-INFO --- borgbackup2-2.0.0b18/PKG-INFO 2025-06-19 13:57:14.289418700 +0200 +++ borgbackup2-2.0.0b19/PKG-INFO 2025-08-02 14:00:25.971163300 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: borgbackup -Version: 2.0.0b18 +Version: 2.0.0b19 Summary: Deduplicated, encrypted, authenticated and compressed backups Author: The Borg Collective (see AUTHORS file) Maintainer-email: Thomas Waldmann diff -Nru borgbackup2-2.0.0b18/src/borg/archive.py borgbackup2-2.0.0b19/src/borg/archive.py --- borgbackup2-2.0.0b18/src/borg/archive.py 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/archive.py 2025-08-02 13:55:43.000000000 +0200 @@ -1215,6 +1215,7 @@ log_json, iec, file_status_printer=None, + files_changed="ctime", ): self.metadata_collector = metadata_collector self.cache = cache @@ -1223,6 +1224,7 @@ self.process_file_chunks = process_file_chunks self.show_progress = show_progress self.print_file_status = file_status_printer or (lambda *args: None) + self.files_changed = files_changed self.hlm = HardLinkManager(id_type=tuple, info_type=(list, type(None))) # (dev, ino) -> chunks or None self.stats = Statistics(output_json=log_json, iec=iec) # threading: done by cache (including progress) @@ -1445,21 +1447,37 @@ if not is_win32: # TODO for win32 with backup_io("fstat2"): st2 = os.fstat(fd) - if is_special_file: + if self.files_changed == "disabled" or is_special_file: # special files: # - fifos change naturally, because they are fed from the other side. no problem. # - blk/chr devices don't change ctime anyway. pass - elif st.st_ctime_ns != st2.st_ctime_ns: - # ctime was changed, this is either a metadata or a data change. - changed_while_backup = True - elif start_reading - TIME_DIFFERS1_NS < st2.st_ctime_ns < end_reading + TIME_DIFFERS1_NS: - # this is to treat a very special race condition, see #3536. - # - file was changed right before st.ctime was determined. - # - then, shortly afterwards, but already while we read the file, the - # file was changed again, but st2.ctime is the same due to ctime granularity. - # when comparing file ctime to local clock, widen interval by TIME_DIFFERS1_NS. - changed_while_backup = True + elif self.files_changed == "ctime": + if st.st_ctime_ns != st2.st_ctime_ns: + # ctime was changed, this is either a metadata or a data change. + changed_while_backup = True + elif ( + start_reading - TIME_DIFFERS1_NS < st2.st_ctime_ns < end_reading + TIME_DIFFERS1_NS + ): + # this is to treat a very special race condition, see #3536. + # - file was changed right before st.ctime was determined. + # - then, shortly afterwards, but already while we read the file, the + # file was changed again, but st2.ctime is the same due to ctime granularity. + # when comparing file ctime to local clock, widen interval by TIME_DIFFERS1_NS. + changed_while_backup = True + elif self.files_changed == "mtime": + if st.st_mtime_ns != st2.st_mtime_ns: + # mtime was changed, this is either a data change. + changed_while_backup = True + elif ( + start_reading - TIME_DIFFERS1_NS < st2.st_mtime_ns < end_reading + TIME_DIFFERS1_NS + ): + # this is to treat a very special race condition, see #3536. + # - file was changed right before st.mtime was determined. + # - then, shortly afterwards, but already while we read the file, the + # file was changed again, but st2.mtime is the same due to mtime granularity. + # when comparing file mtime to local clock, widen interval by TIME_DIFFERS1_NS. + changed_while_backup = True if changed_while_backup: # regular file changed while we backed it up, might be inconsistent/corrupt! if last_try: @@ -1503,7 +1521,7 @@ self.stats = Statistics(output_json=log_json, iec=iec) # threading: done by cache (including progress) self.chunker = get_chunker(*chunker_params, key=key, sparse=False) - self.hlm = HardLinkManager(id_type=str, info_type=list) # path -> chunks + self.hlm = HardLinkManager(id_type=str, info_type=list) # normalized/safe path -> chunks @contextmanager def create_helper(self, tarinfo, status=None, type=None): @@ -1518,8 +1536,11 @@ def s_to_ns(s): return safe_ns(int(float(s) * 1e9)) + # if the tar has names starting with "./", normalize them like borg create also does. + # ./dir/file must become dir/file in the borg archive. + normalized_path = os.path.normpath(tarinfo.name) item = Item( - path=make_path_safe(tarinfo.name), + path=make_path_safe(normalized_path), mode=tarinfo.mode | type, uid=tarinfo.uid, gid=tarinfo.gid, @@ -1572,7 +1593,9 @@ def process_hardlink(self, *, tarinfo, status, type): with self.create_helper(tarinfo, status, type) as (item, status): # create a not hardlinked borg item, reusing the chunks, see HardLinkManager.__doc__ - chunks = self.hlm.retrieve(tarinfo.linkname) + normalized_path = os.path.normpath(tarinfo.linkname) + safe_path = make_path_safe(normalized_path) + chunks = self.hlm.retrieve(safe_path) if chunks is not None: item.chunks = chunks item.get_size(memorize=True, from_chunks=True) @@ -1581,7 +1604,7 @@ def process_file(self, *, tarinfo, status, type, tar): with self.create_helper(tarinfo, status, type) as (item, status): - self.print_file_status(status, tarinfo.name) + self.print_file_status(status, item.path) status = None # we already printed the status fd = tar.extractfile(tarinfo) self.process_file_chunks( @@ -1590,7 +1613,7 @@ item.get_size(memorize=True, from_chunks=True) self.stats.nfiles += 1 # we need to remember ALL files, see HardLinkManager.__doc__ - self.hlm.remember(id=tarinfo.name, info=item.chunks) + self.hlm.remember(id=item.path, info=item.chunks) return status diff -Nru borgbackup2-2.0.0b18/src/borg/archiver/create_cmd.py borgbackup2-2.0.0b19/src/borg/archiver/create_cmd.py --- borgbackup2-2.0.0b18/src/borg/archiver/create_cmd.py 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/archiver/create_cmd.py 2025-08-02 13:55:43.000000000 +0200 @@ -262,6 +262,7 @@ log_json=args.log_json, iec=args.iec, file_status_printer=self.print_file_status, + files_changed=args.files_changed, ) create_inner(archive, cache, fso) else: @@ -611,6 +612,13 @@ 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. + The ``--files-changed`` option controls how Borg detects if a file has changed during backup: + - ctime (default): Use ctime to detect changes. This is the safest option. + - mtime: Use mtime to detect changes. + - disabled: Disable the "file has changed while we backed it up" detection completely. + This is not recommended unless you know what you're doing, as it could lead to + inconsistent backups if files change during the backup process. + The mount points of filesystems or filesystem snapshots should be the same for every creation of a new archive to ensure fast operation. This is because the file cache that is used to determine changed files quickly uses absolute filenames. @@ -889,6 +897,15 @@ help="operate files cache in MODE. default: %s" % FILES_CACHE_MODE_UI_DEFAULT, ) fs_group.add_argument( + "--files-changed", + metavar="MODE", + dest="files_changed", + action=Highlander, + choices=["ctime", "mtime", "disabled"], + default="ctime", + help="specify how to detect if a file has changed during backup (ctime, mtime, disabled). default: ctime", + ) + fs_group.add_argument( "--read-special", dest="read_special", action="store_true", diff -Nru borgbackup2-2.0.0b18/src/borg/chunkers/buzhash64.c borgbackup2-2.0.0b19/src/borg/chunkers/buzhash64.c --- borgbackup2-2.0.0b18/src/borg/chunkers/buzhash64.c 2025-06-19 13:57:13.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/chunkers/buzhash64.c 2025-08-02 14:00:25.000000000 +0200 @@ -4270,7 +4270,7 @@ * self.remaining -= min_size * sum = _buzhash64(self.data + self.position, window_size, self.table) # <<<<<<<<<<<<<< * - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): */ __pyx_t_1 = __pyx_f_4borg_8chunkers_9buzhash64__buzhash64((__pyx_v_self->data + __pyx_v_self->position), __pyx_v_window_size, __pyx_v_self->table); if (unlikely(__pyx_t_1 == ((uint64_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 225, __pyx_L1_error) __pyx_v_sum = __pyx_t_1; @@ -4278,12 +4278,12 @@ /* "borg/chunkers/buzhash64.pyx":227 * sum = _buzhash64(self.data + self.position, window_size, self.table) * - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): # <<<<<<<<<<<<<< + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): # <<<<<<<<<<<<<< * p = self.data + self.position * stop_at = p + self.remaining - window_size */ while (1) { - __pyx_t_7 = (__pyx_v_self->remaining > __pyx_v_self->window_size); + __pyx_t_7 = (__pyx_v_self->remaining > __pyx_v_window_size); if (__pyx_t_7) { } else { __pyx_t_3 = __pyx_t_7; @@ -4311,7 +4311,7 @@ /* "borg/chunkers/buzhash64.pyx":228 * - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): * p = self.data + self.position # <<<<<<<<<<<<<< * stop_at = p + self.remaining - window_size * @@ -4319,7 +4319,7 @@ __pyx_v_p = (__pyx_v_self->data + __pyx_v_self->position); /* "borg/chunkers/buzhash64.pyx":229 - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): * p = self.data + self.position * stop_at = p + self.remaining - window_size # <<<<<<<<<<<<<< * diff -Nru borgbackup2-2.0.0b18/src/borg/chunkers/buzhash64.pyx borgbackup2-2.0.0b19/src/borg/chunkers/buzhash64.pyx --- borgbackup2-2.0.0b18/src/borg/chunkers/buzhash64.pyx 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/chunkers/buzhash64.pyx 2025-08-02 13:55:43.000000000 +0200 @@ -224,7 +224,7 @@ self.remaining -= min_size sum = _buzhash64(self.data + self.position, window_size, self.table) - while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): p = self.data + self.position stop_at = p + self.remaining - window_size diff -Nru borgbackup2-2.0.0b18/src/borg/chunkers/buzhash.c borgbackup2-2.0.0b19/src/borg/chunkers/buzhash.c --- borgbackup2-2.0.0b18/src/borg/chunkers/buzhash.c 2025-06-19 13:57:13.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/chunkers/buzhash.c 2025-08-02 14:00:25.000000000 +0200 @@ -4057,7 +4057,7 @@ * self.remaining -= min_size * sum = _buzhash(self.data + self.position, window_size, self.table) # <<<<<<<<<<<<<< * - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): */ __pyx_t_1 = __pyx_f_4borg_8chunkers_7buzhash__buzhash((__pyx_v_self->data + __pyx_v_self->position), __pyx_v_window_size, __pyx_v_self->table); if (unlikely(__pyx_t_1 == ((uint32_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 248, __pyx_L1_error) __pyx_v_sum = __pyx_t_1; @@ -4065,12 +4065,12 @@ /* "borg/chunkers/buzhash.pyx":250 * sum = _buzhash(self.data + self.position, window_size, self.table) * - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): # <<<<<<<<<<<<<< + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): # <<<<<<<<<<<<<< * p = self.data + self.position * stop_at = p + self.remaining - window_size */ while (1) { - __pyx_t_7 = (__pyx_v_self->remaining > __pyx_v_self->window_size); + __pyx_t_7 = (__pyx_v_self->remaining > __pyx_v_window_size); if (__pyx_t_7) { } else { __pyx_t_3 = __pyx_t_7; @@ -4098,7 +4098,7 @@ /* "borg/chunkers/buzhash.pyx":251 * - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): * p = self.data + self.position # <<<<<<<<<<<<<< * stop_at = p + self.remaining - window_size * @@ -4106,7 +4106,7 @@ __pyx_v_p = (__pyx_v_self->data + __pyx_v_self->position); /* "borg/chunkers/buzhash.pyx":252 - * while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + * while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): * p = self.data + self.position * stop_at = p + self.remaining - window_size # <<<<<<<<<<<<<< * diff -Nru borgbackup2-2.0.0b18/src/borg/chunkers/buzhash.pyx borgbackup2-2.0.0b19/src/borg/chunkers/buzhash.pyx --- borgbackup2-2.0.0b18/src/borg/chunkers/buzhash.pyx 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/chunkers/buzhash.pyx 2025-08-02 13:55:43.000000000 +0200 @@ -247,7 +247,7 @@ self.remaining -= min_size sum = _buzhash(self.data + self.position, window_size, self.table) - while self.remaining > self.window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): + while self.remaining > window_size and (sum & chunk_mask) and not (self.eof and self.remaining <= window_size): p = self.data + self.position stop_at = p + self.remaining - window_size diff -Nru borgbackup2-2.0.0b18/src/borg/chunkers/reader.c borgbackup2-2.0.0b19/src/borg/chunkers/reader.c --- borgbackup2-2.0.0b18/src/borg/chunkers/reader.c 2025-06-19 13:56:09.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/chunkers/reader.c 2025-08-02 13:56:31.000000000 +0200 @@ -2749,7 +2749,7 @@ static const char __pyx_k_src_borg_chunkers_reader_pyx[] = "src/borg/chunkers/reader.pyx"; static const char __pyx_k_7_Q_s_c_Cq_F_F_r_1A_M_A_N_Q_HA[] = "\320\004\032\230)\2407\250-\260~\300Q\330\010\017\210s\220'\230\025\230c\240\023\240C\240q\330\010\014\210F\220!\330\010\014\210F\220!\330\010\017\210r\220\022\220=\240\003\2401\240A\330\010\014\210M\230\021\330\010\014\320\014\034\230A\360\006\000\t\r\210N\230'\240\024\240Q\330\010\014\210H\220A"; static const char __pyx_k_7_Q_z_1_JnAS_Ct_xW_Ja_Ja_q_A_F[] = "\320\004\032\230)\2407\250-\260~\300Q\330\010\017\210z\230\022\2301\330\010\014\210J\220n\240A\240S\250\004\250C\250t\260:\270[\310\007\310x\320W\\\320\\]\330\010\014\210J\220a\330\010\014\210J\220a\330\010\014\320\014\037\230q\330\010\014\320\014\034\230A\330\010\014\210F\220!\330\010\014\210F\220!\330\010\014\210H\220A"; -static const char __pyx_k_A_4_S_1_G9A_d_2Q_t4_A_4t1_5_e3k[] = "\200A\360&\000\t\014\2104\210~\230S\240\001\330\014\020\220\n\230!\330\014\020\220\n\230!\330\014\020\320\020#\2401\330\014\020\320\020 \240\004\240G\2509\260A\360\006\000\t\017\210d\320\022#\2402\240Q\330\014\017\210t\2204\220}\240A\340\020\021\360\006\000\t\014\2104\210t\2201\330\014\023\2205\230\001\230\025\230e\2403\240k\260\021\360\006\000\t\022\220\031\230!\330\010\033\2301\230F\240$\240a\330\010\025\220Q\360\006\000\t\024\2201\330\010\023\2201\330\010\024\220A\360\006\000\t\017\210k\230\022\230>\250\024\250T\260\021\330\014\024\220D\230\007\230q\240\001\330\014\031\230\025\230e\2401\240A\330\014\031\230\025\230e\2401\240A\330\014\023\2205\230\001\360\006\000\r\020\210{\230#\230Q\330\020\033\2301\330\021\034\230C\230q\330\020\033\2301\330\021\034\230C\230q\330\020\034\230A\340\020\026\220j\240\001\240\022\320#@\300\001\360\006\000\r\031\230\013\2402\240T\250\021\330\014\031\230\021\230+\240^\2602\260Q\360\006\000\r\020\210{\230#\230Q\330\020\027\220u\230G\2401\340\020\026\220g\230Q\230d\240!\2404\240x\250t\2608\2702\270Q\360\006\000\021\024\2201\330\024\032\230'\240\021\240&\250\002\250!\360\006\000\r\033\230!\360\006\000\r\020\210x\220r\230\021\330\020\024\220K\230q\340\020\024\220J\230a\330\020\024\220G\2304\230q\240\001\340\014\020\320\020$\240A\360\006\000\t\014\2101\340\014\023\2205\230\001\230\025\230a\230y\250\005\250\\\270\033\300A\330\r\016\340\014\023\2205\230\001\230\026\230u\240L\260\013\2701\360\006\000\r\024\2205\230\001\230\026\230u\240L\260\013\2701"; +static const char __pyx_k_A_4_S_1_G9A_d_2Q_t4_A_4t1_5_e3k[] = "\200A\360&\000\t\014\2104\210~\230S\240\001\330\014\020\220\n\230!\330\014\020\220\n\230!\330\014\020\320\020#\2401\330\014\020\320\020 \240\004\240G\2509\260A\360\006\000\t\017\210d\320\022#\2402\240Q\330\014\017\210t\2204\220}\240A\340\020\021\360\006\000\t\014\2104\210t\2201\330\014\023\2205\230\001\230\025\230e\2403\240k\260\021\360\006\000\t\022\220\031\230!\330\010\033\2301\230F\240$\240a\330\010\025\220Q\360\006\000\t\024\2201\330\010\023\2201\330\010\024\220A\360\006\000\t\017\210k\230\022\230>\250\024\250T\260\021\330\014\024\220D\230\007\230q\240\001\330\014\031\230\025\230e\2401\240A\330\014\031\230\025\230e\2401\240A\330\014\023\2205\230\001\360\006\000\r\020\210{\230#\230Q\330\020\033\2301\330\021\034\230C\230q\330\020\033\2301\330\021\034\230C\230q\330\020\034\230A\340\020\026\220j\240\001\240\022\320#@\300\001\360\006\000\r\031\230\013\2402\240T\250\021\330\014\031\230\021\230+\240^\2602\260Q\360\006\000\r\020\210{\230#\230Q\330\020\027\220u\230G\2401\340\020\026\220g\230Q\230d\240!\2404\240x\250t\2608\2702\270Q\360\014\000\021\027\220g\230Q\230f\240B\240a\340\014\032\230!\360\006\000\r\020\210x\220r\230\021\330\020\024\220K\230q\340\020\024\220J\230a\330\020\024\220G\2304\230q\240\001\340\014\020\320\020$\240A\360\006\000\t\014\2101\340\014\023\2205\230\001\230\025\230a\230y\250\005\250\\\270\033\300A\330\r\016\340\014\023\2205\230\001\230\026\230u\240L\260\013\2701\360\006\000\r\024\2205\230\001\230\026\230u\240L\260\013\2701"; static const char __pyx_k_Chunk_namedtuple_meta_is_always[] = " Chunk namedtuple\n\n meta is always a dictionary, data depends on allocation.\n\n data chunk read from a DATA range of a file (not from a sparse hole):\n meta = {'allocation' = CH_DATA, 'size' = size_of_chunk }\n data = read_data [bytes or memoryview]\n\n all-zero chunk read from a DATA range of a file (not from a sparse hole, but detected to be all-zero):\n meta = {'allocation' = CH_ALLOC, 'size' = size_of_chunk }\n data = None\n\n all-zero chunk from a HOLE range of a file (from a sparse hole):\n meta = {'allocation' = CH_HOLE, 'size' = size_of_chunk }\n data = None\n"; static const char __pyx_k_This_is_a_buffered_reader_for_f[] = "\n This is a buffered reader for file data.\n\n It maintains a buffer that is filled with Chunks from the FileFMAPReader.blockify generator.\n The data in that buffer is consumed by clients calling FileReader.read, which returns a Chunk.\n\n Most complexity in here comes from the desired size when a user calls FileReader.read does\n not need to match the Chunk sizes we got from the FileFMAPReader.\n "; static const char __pyx_k_This_is_for_reading_blocks_from[] = "\n This is for reading blocks from a file.\n\n It optionally supports:\n\n - using a sparsemap to read only data ranges and seek over hole ranges\n for sparse files.\n - using an externally given filemap to read only specific ranges from\n a file.\n\n Note: the last block of a data or hole range may be less than the read_size,\n this is supported and not considered to be an error.\n "; @@ -8020,7 +8020,7 @@ * # For data chunks, add the actual data * result.extend(data[self.offset:self.offset + to_read]) # <<<<<<<<<<<<<< * else: - * # For non-data chunks, add zeros if we've seen a data chunk + * # For non-data chunks, always add zeros to the result. */ __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_offset); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 304, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); @@ -8048,91 +8048,73 @@ goto __pyx_L13; } - /* "borg/chunkers/reader.pyx":307 - * else: - * # For non-data chunks, add zeros if we've seen a data chunk - * if has_data: # <<<<<<<<<<<<<< - * result.extend(b'\0' * to_read) - * # Otherwise, we'll just track the size without adding data -*/ - /*else*/ { - if (__pyx_v_has_data) { - - /* "borg/chunkers/reader.pyx":308 - * # For non-data chunks, add zeros if we've seen a data chunk - * if has_data: - * result.extend(b'\0' * to_read) # <<<<<<<<<<<<<< - * # Otherwise, we'll just track the size without adding data + /* "borg/chunkers/reader.pyx":310 + * # if there was at least one CH_DATA chunk contributing to the result, + * # otherwise we will yield a CH_HOLE or CH_ALLOC chunk. + * result.extend(b'\0' * to_read) # <<<<<<<<<<<<<< * + * bytes_read += to_read */ - __pyx_t_4 = PyNumber_Multiply(__pyx_mstate_global->__pyx_kp_b__2, __pyx_v_to_read); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 308, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_8 = __Pyx_CallUnboundCMethod1(&__pyx_mstate_global->__pyx_umethod_PyByteArray_Type__extend, __pyx_v_result, __pyx_t_4); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 308, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - - /* "borg/chunkers/reader.pyx":307 - * else: - * # For non-data chunks, add zeros if we've seen a data chunk - * if has_data: # <<<<<<<<<<<<<< - * result.extend(b'\0' * to_read) - * # Otherwise, we'll just track the size without adding data -*/ - } + /*else*/ { + __pyx_t_4 = PyNumber_Multiply(__pyx_mstate_global->__pyx_kp_b__2, __pyx_v_to_read); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_8 = __Pyx_CallUnboundCMethod1(&__pyx_mstate_global->__pyx_umethod_PyByteArray_Type__extend, __pyx_v_result, __pyx_t_4); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 310, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; } __pyx_L13:; - /* "borg/chunkers/reader.pyx":311 - * # Otherwise, we'll just track the size without adding data + /* "borg/chunkers/reader.pyx":312 + * result.extend(b'\0' * to_read) * * bytes_read += to_read # <<<<<<<<<<<<<< * * # Update offset or remove chunk if fully consumed */ - __pyx_t_8 = PyNumber_InPlaceAdd(__pyx_v_bytes_read, __pyx_v_to_read); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 311, __pyx_L1_error) + __pyx_t_8 = PyNumber_InPlaceAdd(__pyx_v_bytes_read, __pyx_v_to_read); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 312, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_8); __Pyx_DECREF_SET(__pyx_v_bytes_read, __pyx_t_8); __pyx_t_8 = 0; - /* "borg/chunkers/reader.pyx":314 + /* "borg/chunkers/reader.pyx":315 * * # Update offset or remove chunk if fully consumed * if to_read < available: # <<<<<<<<<<<<<< * self.offset += to_read * else: */ - __pyx_t_8 = PyObject_RichCompare(__pyx_v_to_read, __pyx_v_available, Py_LT); __Pyx_XGOTREF(__pyx_t_8); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 314, __pyx_L1_error) - __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 314, __pyx_L1_error) + __pyx_t_8 = PyObject_RichCompare(__pyx_v_to_read, __pyx_v_available, Py_LT); __Pyx_XGOTREF(__pyx_t_8); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 315, __pyx_L1_error) + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_8); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 315, __pyx_L1_error) __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; if (__pyx_t_2) { - /* "borg/chunkers/reader.pyx":315 + /* "borg/chunkers/reader.pyx":316 * # Update offset or remove chunk if fully consumed * if to_read < available: * self.offset += to_read # <<<<<<<<<<<<<< * else: * self.offset = 0 */ - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_offset); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 315, __pyx_L1_error) + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_offset); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 316, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_8); - __pyx_t_4 = PyNumber_InPlaceAdd(__pyx_t_8, __pyx_v_to_read); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 315, __pyx_L1_error) + __pyx_t_4 = PyNumber_InPlaceAdd(__pyx_t_8, __pyx_v_to_read); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 316, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_offset, __pyx_t_4) < 0) __PYX_ERR(0, 315, __pyx_L1_error) + if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_offset, __pyx_t_4) < 0) __PYX_ERR(0, 316, __pyx_L1_error) __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - /* "borg/chunkers/reader.pyx":314 + /* "borg/chunkers/reader.pyx":315 * * # Update offset or remove chunk if fully consumed * if to_read < available: # <<<<<<<<<<<<<< * self.offset += to_read * else: */ - goto __pyx_L15; + goto __pyx_L14; } - /* "borg/chunkers/reader.pyx":317 + /* "borg/chunkers/reader.pyx":318 * self.offset += to_read * else: * self.offset = 0 # <<<<<<<<<<<<<< @@ -8140,41 +8122,41 @@ * */ /*else*/ { - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_offset, __pyx_mstate_global->__pyx_int_0) < 0) __PYX_ERR(0, 317, __pyx_L1_error) + if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_offset, __pyx_mstate_global->__pyx_int_0) < 0) __PYX_ERR(0, 318, __pyx_L1_error) - /* "borg/chunkers/reader.pyx":318 + /* "borg/chunkers/reader.pyx":319 * else: * self.offset = 0 * self.buffer.pop(0) # <<<<<<<<<<<<<< * * self.remaining_bytes -= to_read */ - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_buffer); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 318, __pyx_L1_error) + __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_buffer); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 319, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); - __pyx_t_8 = __Pyx_PyObject_PopIndex(__pyx_t_4, __pyx_mstate_global->__pyx_int_0, 0, 1, Py_ssize_t, PyLong_FromSsize_t); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 318, __pyx_L1_error) + __pyx_t_8 = __Pyx_PyObject_PopIndex(__pyx_t_4, __pyx_mstate_global->__pyx_int_0, 0, 1, Py_ssize_t, PyLong_FromSsize_t); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 319, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_8); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; } - __pyx_L15:; + __pyx_L14:; - /* "borg/chunkers/reader.pyx":320 + /* "borg/chunkers/reader.pyx":321 * self.buffer.pop(0) * * self.remaining_bytes -= to_read # <<<<<<<<<<<<<< * * # Determine the allocation type of the resulting chunk */ - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_remaining_bytes); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 320, __pyx_L1_error) + __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_remaining_bytes); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 321, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_8); - __pyx_t_4 = PyNumber_InPlaceSubtract(__pyx_t_8, __pyx_v_to_read); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 320, __pyx_L1_error) + __pyx_t_4 = PyNumber_InPlaceSubtract(__pyx_t_8, __pyx_v_to_read); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 321, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_remaining_bytes, __pyx_t_4) < 0) __PYX_ERR(0, 320, __pyx_L1_error) + if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_remaining_bytes, __pyx_t_4) < 0) __PYX_ERR(0, 321, __pyx_L1_error) __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; } - /* "borg/chunkers/reader.pyx":323 + /* "borg/chunkers/reader.pyx":324 * * # Determine the allocation type of the resulting chunk * if has_data: # <<<<<<<<<<<<<< @@ -8183,7 +8165,7 @@ */ if (__pyx_v_has_data) { - /* "borg/chunkers/reader.pyx":325 + /* "borg/chunkers/reader.pyx":326 * if has_data: * # If any chunk was CH_DATA, the result is CH_DATA * return Chunk(bytes(result), size=bytes_read, allocation=CH_DATA) # <<<<<<<<<<<<<< @@ -8192,7 +8174,7 @@ */ __Pyx_XDECREF(__pyx_r); __pyx_t_8 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_Chunk_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 325, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_Chunk_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 326, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_t_7 = NULL; __Pyx_INCREF((PyObject *)(&PyBytes_Type)); @@ -8203,10 +8185,10 @@ __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 325, __pyx_L1_error) + if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 326, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); } - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_CH_DATA); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 325, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_CH_DATA); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 326, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_9); __pyx_t_5 = 1; #if CYTHON_UNPACK_METHODS @@ -8222,24 +8204,24 @@ #endif { PyObject *__pyx_callargs[2 + ((CYTHON_VECTORCALL) ? 2 : 0)] = {__pyx_t_8, __pyx_t_3}; - __pyx_t_7 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 325, __pyx_L1_error) + __pyx_t_7 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 326, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); - if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_size, __pyx_v_bytes_read, __pyx_t_7, __pyx_callargs+2, 0) < 0) __PYX_ERR(0, 325, __pyx_L1_error) - if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_allocation, __pyx_t_9, __pyx_t_7, __pyx_callargs+2, 1) < 0) __PYX_ERR(0, 325, __pyx_L1_error) + if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_size, __pyx_v_bytes_read, __pyx_t_7, __pyx_callargs+2, 0) < 0) __PYX_ERR(0, 326, __pyx_L1_error) + if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_allocation, __pyx_t_9, __pyx_t_7, __pyx_callargs+2, 1) < 0) __PYX_ERR(0, 326, __pyx_L1_error) __pyx_t_4 = __Pyx_Object_Vectorcall_CallFromBuilder(__pyx_t_1, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET), __pyx_t_7); __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 325, __pyx_L1_error) + if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 326, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); } __pyx_r = __pyx_t_4; __pyx_t_4 = 0; goto __pyx_L0; - /* "borg/chunkers/reader.pyx":323 + /* "borg/chunkers/reader.pyx":324 * * # Determine the allocation type of the resulting chunk * if has_data: # <<<<<<<<<<<<<< @@ -8248,7 +8230,7 @@ */ } - /* "borg/chunkers/reader.pyx":326 + /* "borg/chunkers/reader.pyx":327 * # If any chunk was CH_DATA, the result is CH_DATA * return Chunk(bytes(result), size=bytes_read, allocation=CH_DATA) * elif has_hole: # <<<<<<<<<<<<<< @@ -8257,7 +8239,7 @@ */ if (__pyx_v_has_hole) { - /* "borg/chunkers/reader.pyx":328 + /* "borg/chunkers/reader.pyx":329 * elif has_hole: * # If any chunk was CH_HOLE (and none were CH_DATA), the result is CH_HOLE * return Chunk(None, size=bytes_read, allocation=CH_HOLE) # <<<<<<<<<<<<<< @@ -8266,9 +8248,9 @@ */ __Pyx_XDECREF(__pyx_r); __pyx_t_1 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_Chunk_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_Chunk_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 329, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_CH_HOLE); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 328, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_CH_HOLE); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 329, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_9); __pyx_t_5 = 1; #if CYTHON_UNPACK_METHODS @@ -8284,23 +8266,23 @@ #endif { PyObject *__pyx_callargs[2 + ((CYTHON_VECTORCALL) ? 2 : 0)] = {__pyx_t_1, Py_None}; - __pyx_t_3 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 328, __pyx_L1_error) + __pyx_t_3 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 329, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); - if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_size, __pyx_v_bytes_read, __pyx_t_3, __pyx_callargs+2, 0) < 0) __PYX_ERR(0, 328, __pyx_L1_error) - if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_allocation, __pyx_t_9, __pyx_t_3, __pyx_callargs+2, 1) < 0) __PYX_ERR(0, 328, __pyx_L1_error) + if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_size, __pyx_v_bytes_read, __pyx_t_3, __pyx_callargs+2, 0) < 0) __PYX_ERR(0, 329, __pyx_L1_error) + if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_allocation, __pyx_t_9, __pyx_t_3, __pyx_callargs+2, 1) < 0) __PYX_ERR(0, 329, __pyx_L1_error) __pyx_t_4 = __Pyx_Object_Vectorcall_CallFromBuilder(__pyx_t_7, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET), __pyx_t_3); __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 328, __pyx_L1_error) + if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 329, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); } __pyx_r = __pyx_t_4; __pyx_t_4 = 0; goto __pyx_L0; - /* "borg/chunkers/reader.pyx":326 + /* "borg/chunkers/reader.pyx":327 * # If any chunk was CH_DATA, the result is CH_DATA * return Chunk(bytes(result), size=bytes_read, allocation=CH_DATA) * elif has_hole: # <<<<<<<<<<<<<< @@ -8309,7 +8291,7 @@ */ } - /* "borg/chunkers/reader.pyx":331 + /* "borg/chunkers/reader.pyx":332 * else: * # Otherwise, all chunks were CH_ALLOC * return Chunk(None, size=bytes_read, allocation=CH_ALLOC) # <<<<<<<<<<<<<< @@ -8319,9 +8301,9 @@ /*else*/ { __Pyx_XDECREF(__pyx_r); __pyx_t_7 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_Chunk_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 331, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_Chunk_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 332, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_CH_ALLOC); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 331, __pyx_L1_error) + __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_CH_ALLOC); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 332, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_9); __pyx_t_5 = 1; #if CYTHON_UNPACK_METHODS @@ -8337,16 +8319,16 @@ #endif { PyObject *__pyx_callargs[2 + ((CYTHON_VECTORCALL) ? 2 : 0)] = {__pyx_t_7, Py_None}; - __pyx_t_1 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 331, __pyx_L1_error) + __pyx_t_1 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 332, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); - if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_size, __pyx_v_bytes_read, __pyx_t_1, __pyx_callargs+2, 0) < 0) __PYX_ERR(0, 331, __pyx_L1_error) - if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_allocation, __pyx_t_9, __pyx_t_1, __pyx_callargs+2, 1) < 0) __PYX_ERR(0, 331, __pyx_L1_error) + if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_size, __pyx_v_bytes_read, __pyx_t_1, __pyx_callargs+2, 0) < 0) __PYX_ERR(0, 332, __pyx_L1_error) + if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_allocation, __pyx_t_9, __pyx_t_1, __pyx_callargs+2, 1) < 0) __PYX_ERR(0, 332, __pyx_L1_error) __pyx_t_4 = __Pyx_Object_Vectorcall_CallFromBuilder(__pyx_t_3, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET), __pyx_t_1); __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 331, __pyx_L1_error) + if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 332, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); } __pyx_r = __pyx_t_4; @@ -9929,7 +9911,7 @@ __pyx_mstate_global->__pyx_codeobj_tab[9] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_src_borg_chunkers_reader_pyx, __pyx_mstate->__pyx_n_u_fill_buffer, __pyx_k_A_4_S_1_D_Q_waq_E_aq_1_1, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[9])) goto bad; } { - const __Pyx_PyCode_New_function_description descr = {2, 0, 0, 14, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 234, 467}; + const __Pyx_PyCode_New_function_description descr = {2, 0, 0, 14, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 234, 460}; PyObject* const varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_size, __pyx_mstate->__pyx_n_u_result, __pyx_mstate->__pyx_n_u_bytes_to_read, __pyx_mstate->__pyx_n_u_bytes_read, __pyx_mstate->__pyx_n_u_has_data, __pyx_mstate->__pyx_n_u_has_hole, __pyx_mstate->__pyx_n_u_has_alloc, __pyx_mstate->__pyx_n_u_chunk, __pyx_mstate->__pyx_n_u_chunk_size, __pyx_mstate->__pyx_n_u_allocation, __pyx_mstate->__pyx_n_u_data, __pyx_mstate->__pyx_n_u_available, __pyx_mstate->__pyx_n_u_to_read}; __pyx_mstate_global->__pyx_codeobj_tab[10] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_src_borg_chunkers_reader_pyx, __pyx_mstate->__pyx_n_u_read, __pyx_k_A_4_S_1_G9A_d_2Q_t4_A_4t1_5_e3k, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[10])) goto bad; } diff -Nru borgbackup2-2.0.0b18/src/borg/chunkers/reader.pyx borgbackup2-2.0.0b19/src/borg/chunkers/reader.pyx --- borgbackup2-2.0.0b18/src/borg/chunkers/reader.pyx 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/chunkers/reader.pyx 2025-08-02 13:55:43.000000000 +0200 @@ -303,10 +303,11 @@ # For data chunks, add the actual data result.extend(data[self.offset:self.offset + to_read]) else: - # For non-data chunks, add zeros if we've seen a data chunk - if has_data: - result.extend(b'\0' * to_read) - # Otherwise, we'll just track the size without adding data + # For non-data chunks, always add zeros to the result. + # We will only yield a CH_DATA chunk with the result bytes, + # if there was at least one CH_DATA chunk contributing to the result, + # otherwise we will yield a CH_HOLE or CH_ALLOC chunk. + result.extend(b'\0' * to_read) bytes_read += to_read diff -Nru borgbackup2-2.0.0b18/src/borg/crypto/low_level.c borgbackup2-2.0.0b19/src/borg/crypto/low_level.c --- borgbackup2-2.0.0b18/src/borg/crypto/low_level.c 2025-06-19 13:57:13.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/crypto/low_level.c 2025-08-02 14:00:25.000000000 +0200 @@ -4,9 +4,9 @@ { "distutils": { "depends": [ - "/opt/homebrew/Cellar/openssl@3/3.5.0/include/openssl/crypto.h", - "/opt/homebrew/Cellar/openssl@3/3.5.0/include/openssl/evp.h", - "/opt/homebrew/Cellar/openssl@3/3.5.0/include/openssl/opensslv.h" + "/opt/homebrew/Cellar/openssl@3/3.5.1/include/openssl/crypto.h", + "/opt/homebrew/Cellar/openssl@3/3.5.1/include/openssl/evp.h", + "/opt/homebrew/Cellar/openssl@3/3.5.1/include/openssl/opensslv.h" ], "extra_compile_args": [ "-Wall", @@ -15,13 +15,13 @@ "-Wno-unreachable-code-fallthrough" ], "include_dirs": [ - "/opt/homebrew/Cellar/openssl@3/3.5.0/include" + "/opt/homebrew/Cellar/openssl@3/3.5.1/include" ], "libraries": [ "crypto" ], "library_dirs": [ - "/opt/homebrew/Cellar/openssl@3/3.5.0/lib" + "/opt/homebrew/Cellar/openssl@3/3.5.1/lib" ], "name": "borg.crypto.low_level", "sources": [ diff -Nru borgbackup2-2.0.0b18/src/borg/helpers/parseformat.py borgbackup2-2.0.0b19/src/borg/helpers/parseformat.py --- borgbackup2-2.0.0b18/src/borg/helpers/parseformat.py 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/helpers/parseformat.py 2025-08-02 13:55:43.000000000 +0200 @@ -545,11 +545,11 @@ name = re.sub(r"[^\w]", "_", self.path.rstrip("/")) if self.proto not in ("file", "socket", "rclone"): name = re.sub(r"[^\w]", "_", self.host) + "__" + name - if len(name) > 100: + if len(name) > 120: # Limit file names to some reasonable length. Most file systems # limit them to 255 [unit of choice]; due to variations in unicode # handling we truncate to 100 *characters*. - name = name[:100] + name = name[:120] return os.path.join(get_keys_dir(), name) def __repr__(self): diff -Nru borgbackup2-2.0.0b18/src/borg/testsuite/archiver/debug_cmds_test.py borgbackup2-2.0.0b19/src/borg/testsuite/archiver/debug_cmds_test.py --- borgbackup2-2.0.0b18/src/borg/testsuite/archiver/debug_cmds_test.py 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/testsuite/archiver/debug_cmds_test.py 2025-08-02 13:55:43.000000000 +0200 @@ -1,9 +1,6 @@ import json import os import pstats -import sys - -import pytest from ...constants import * # NOQA from .. import changedir @@ -13,7 +10,6 @@ pytest_generate_tests = lambda metafunc: generate_archiver_tests(metafunc, kinds="local,remote,binary") # NOQA -@pytest.mark.skipif(sys.version_info[:3] >= (3, 14, 0), reason="cProfile.Profile broken in Python 3.14.0b2") def test_debug_profile(archivers, request): archiver = request.getfixturevalue(archivers) create_test_files(archiver.input_path) diff -Nru borgbackup2-2.0.0b18/src/borg/testsuite/archiver/tar_cmds_test.py borgbackup2-2.0.0b19/src/borg/testsuite/archiver/tar_cmds_test.py --- borgbackup2-2.0.0b18/src/borg/testsuite/archiver/tar_cmds_test.py 2025-06-19 13:54:56.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/testsuite/archiver/tar_cmds_test.py 2025-08-02 13:55:43.000000000 +0200 @@ -211,6 +211,34 @@ assert os.listdir("output") == ["file1"] +@requires_gnutar +def test_import_tar_with_dotslash_paths(archivers, request): + """Test that paths starting with './' are normalized during import-tar.""" + archiver = request.getfixturevalue(archivers) + # Create a simple directory structure + create_regular_file(archiver.input_path, "dir/file") + + # Create a tar file with paths starting with './' + with changedir("input"): + # Directly use a path that starts with './' + subprocess.check_call(["tar", "cf", "dotslash.tar", "./dir"]) + + # Verify the tar file contains paths with './' prefix + tar_content = subprocess.check_output(["tar", "tf", "dotslash.tar"]).decode() + assert "./dir" in tar_content + assert "./dir/file" in tar_content + + # Import the tar file into a Borg repository + cmd(archiver, "repo-create", "--encryption=none") + cmd(archiver, "import-tar", "dotslash", "input/dotslash.tar") + + # List the archive contents and verify no paths start with './' + output = cmd(archiver, "list", "--format={path}{NL}", "dotslash") + assert "./dir" not in output + assert "dir" in output + assert "dir/file" in output + + def test_roundtrip_pax_borg(archivers, request): archiver = request.getfixturevalue(archivers) create_test_files(archiver.input_path) diff -Nru borgbackup2-2.0.0b18/src/borg/testsuite/chunkers/interaction_test.py borgbackup2-2.0.0b19/src/borg/testsuite/chunkers/interaction_test.py --- borgbackup2-2.0.0b18/src/borg/testsuite/chunkers/interaction_test.py 1970-01-01 01:00:00.000000000 +0100 +++ borgbackup2-2.0.0b19/src/borg/testsuite/chunkers/interaction_test.py 2025-08-02 13:55:43.000000000 +0200 @@ -0,0 +1,70 @@ +import os +import pytest +from io import BytesIO + +from ...chunkers import get_chunker +from ...constants import * # NOQA + + +@pytest.mark.parametrize( + "chunker_params", + [ + (CH_FIXED, 1048576, 0), # == reader_block_size + (CH_FIXED, 1048576 // 2, 0), # reader_block_size / N + (CH_FIXED, 1048576 * 2, 0), # N * reader_block_size + (CH_FIXED, 1234567, 0), # does not fit well, larger than reader_block_size + (CH_FIXED, 123456, 0), # does not fit well, smaller than reader_block_size + (CH_BUZHASH, CHUNK_MIN_EXP, CHUNK_MAX_EXP, HASH_MASK_BITS, HASH_WINDOW_SIZE), + (CH_BUZHASH64, CHUNK_MIN_EXP, CHUNK_MAX_EXP, HASH_MASK_BITS, HASH_WINDOW_SIZE), + ], +) +def test_reader_chunker_interaction(chunker_params): + """ + Test that chunking random/zero data produces chunks that can be reassembled to match the original data. + + If one of these fails, there is likely a problem with buffer management. + """ + # Generate some data + data_size = 6 * 12341234 + random_data = os.urandom(data_size // 3) + b"\0" * (data_size // 3) + os.urandom(data_size // 3) + + # Chunk the data + chunker = get_chunker(*chunker_params) + data_file = BytesIO(random_data) + chunks = list(chunker.chunkify(data_file)) + + data_chunks = 0 + hole_chunks = 0 + alloc_chunks = 0 + for chunk in chunks: + if chunk.meta["allocation"] == CH_DATA: + data_chunks += 1 + elif chunk.meta["allocation"] == CH_HOLE: + hole_chunks += 1 + elif chunk.meta["allocation"] == CH_ALLOC: + alloc_chunks += 1 + + assert data_chunks > 0, "No data chunks found" + assert alloc_chunks > 0, "No alloc chunks found" + assert hole_chunks == 0, "Hole chunks found, this is not expected!" + + # Reassemble the chunks + reassembled = BytesIO() + for i, chunk in enumerate(chunks): + if chunk.meta["allocation"] == CH_DATA: + # For data chunks, write the actual data + reassembled.write(bytes(chunk.data)) + elif chunk.meta["allocation"] in (CH_HOLE, CH_ALLOC): + # For hole or alloc chunks, write zeros + reassembled.write(b"\0" * chunk.meta["size"]) + + # Check that the reassembled data has the correct size + reassembled_size = reassembled.tell() + assert ( + reassembled_size == data_size + ), f"Reassembled data size ({reassembled_size}) does not equal original data size ({data_size})" + + # Verify that the reassembled data matches the original data + reassembled.seek(0) + reassembled_data = reassembled.read() + assert reassembled_data == random_data, "Reassembled data does not match original data" diff -Nru borgbackup2-2.0.0b18/src/borg/_version.py borgbackup2-2.0.0b19/src/borg/_version.py --- borgbackup2-2.0.0b18/src/borg/_version.py 2025-06-19 13:57:14.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borg/_version.py 2025-08-02 14:00:25.000000000 +0200 @@ -1 +1 @@ -__version__ = version = '2.0.0b18' +__version__ = version = '2.0.0b19' diff -Nru borgbackup2-2.0.0b18/src/borgbackup.egg-info/PKG-INFO borgbackup2-2.0.0b19/src/borgbackup.egg-info/PKG-INFO --- borgbackup2-2.0.0b18/src/borgbackup.egg-info/PKG-INFO 2025-06-19 13:57:14.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borgbackup.egg-info/PKG-INFO 2025-08-02 14:00:25.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: borgbackup -Version: 2.0.0b18 +Version: 2.0.0b19 Summary: Deduplicated, encrypted, authenticated and compressed backups Author: The Borg Collective (see AUTHORS file) Maintainer-email: Thomas Waldmann diff -Nru borgbackup2-2.0.0b18/src/borgbackup.egg-info/SOURCES.txt borgbackup2-2.0.0b19/src/borgbackup.egg-info/SOURCES.txt --- borgbackup2-2.0.0b18/src/borgbackup.egg-info/SOURCES.txt 2025-06-19 13:57:14.000000000 +0200 +++ borgbackup2-2.0.0b19/src/borgbackup.egg-info/SOURCES.txt 2025-08-02 14:00:25.000000000 +0200 @@ -408,6 +408,7 @@ src/borg/testsuite/chunkers/failing_test.py src/borg/testsuite/chunkers/fixed_self_test.py src/borg/testsuite/chunkers/fixed_test.py +src/borg/testsuite/chunkers/interaction_test.py src/borg/testsuite/chunkers/reader_test.py src/borg/testsuite/crypto/__init__.py src/borg/testsuite/crypto/crypto_test.py