11579 Commits
Author SHA1 Message Date
Mrityunjay Raj 6dc98e6d85 check: --repair salvages only packs still present and keeps the pack records current on errors, refs #10026 2026-09-30 04:43:21 +05:30
Mrityunjay Raj 42678c7885 check: --repair salvages the packs recorded corrupt, refs #10026 2026-09-30 04:43:21 +05:30
Mrityunjay Raj e7b17fa84a check: do not depend on archive1 surviving the corrupt pack in the index rebuild test, refs #10434 2026-09-30 04:16:47 +05:30
Mrityunjay Raj a0ebb7e8a1 docs: packs: address review feedback 2026-09-30 01:14:34 +05:30
Mrityunjay Raj e178bc3902 check: test a full --repair with a corrupt index and a corrupt pack, refs #10434 2026-09-30 01:08:40 +05:30
Thomas WaldmannandClaude Opus 5.5 fd71c9eca0 completion: no directory completion for repository URLs, fixes #10460
-r/--repo and --other-repo completed local directories even when the value
already started with a URL scheme like ssh:// or rclone:. In fish, this
offered e.g. "ssh://etc/" (fish completes the part after the ":" as a path),
tcsh printed "ssh:// not found".

Now, a URL scheme other than file: (the ones Location parses as a URL) gets
no completion in any shell, while local paths still complete directories:

- bash, zsh, fish: new _borg_complete_repo_dirs helper
- tcsh: a leading completion rule completing nothing for a URL, it is used
  before the directory rules of the repository options.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 21:18:34 +02:00
TW a586f69313 Merge pull request #10470 from ThomasWaldmann/msgpack-123
support msgpack 1.2.3
2026-09-29 21:07:28 +02:00
Mrityunjay Raj 8d0ab1b3e1 check: a full --repair rebuilds a corrupt index once, in the archives phase, fixes #10434 2026-09-30 00:30:37 +05:30
Mrityunjay Raj ca00a1255a compact: suggest a full check --repair for unindexed pack bytes, fixes #10429 2026-09-30 00:30:27 +05:30
Thomas WaldmannandClaude Opus 5.5 e84d7ac7a8 support msgpack 1.2.3
msgpack 1.2.3 brings fixes relevant to borg's usage of the C extension:
memory leaks when map key validation or container hooks fail
(GHSA-j586-36cw-2gc2) and a use-after-free when cleaning up an
incomplete Unpacker.skip().

The C Unpacker now raises ValueError when switching between unpack,
skip, header readers or read_bytes() while an object is incomplete.
borg only uses feed() plus unpack()/iteration (and RobustUnpacker
creates a fresh Unpacker on each resync attempt), so this does not
affect borg.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 20:29:15 +02:00
TW 1c5a3c37f0 Merge pull request #10468 from ThomasWaldmann/solaris-xattr-devices
illumos/Solaris: do not open device nodes to get their xattrs
2026-09-29 20:08:44 +02:00
Thomas WaldmannandClaude Opus 5.5 b03b0964b2 illumos/Solaris: do not open device nodes to get their xattrs
Reaching the attribute directory of a file requires opening the file.
For a block or character device node, that runs the open routine of
its driver, which might fail (ENXIO if there is no such device, as
for the device nodes created by the archiver tests when run as root),
block or have side effects (e.g. a tape rewinding on close).

Treat device nodes as not supporting extended attributes instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 18:03:37 +02:00
TW c195377132 Merge pull request #10462 from borgbackup/dependabot/github_actions/actions-83e5d110ae
build(deps): bump the actions group with 3 updates
2026-09-29 14:41:31 +02:00
TW 153d10a862 Merge pull request #10461 from borgbackup/dependabot/pip/requirements.d/pip-dependencies-6b5638b15d
build(deps-dev): bump the pip-dependencies group in /requirements.d with 4 updates
2026-09-29 10:59:02 +02:00
Mrityunjay Raj b1370be663 RobustUnpacker: resync in linear time, fixes #10459
After resync(), __next__ joined all data fed so far and searched it from
offset 0, advancing with data = data[1:], which copies the remaining
data for every byte. Resyncing over a big item's chunk list did not
finish.

Search a bytearray via a memoryview, continue at the offset where the
last search stopped and drop the searched data. Offsets where the fed
data ends within the msgpacked object (incomplete item starts) are tried
again after each feed(), the last MAX_ITEM_HEADER_LEN bytes are checked
again by valid_msgpacked_dict after the next feed().

Incomplete item starts more than MAX_PENDING_ITEM_LEN (4 MiB) before the
end of the fed data are dropped, so an item > 4 MiB starting right at a
resync point is not recovered.

Try item starts with unpackb on a memoryview slice, its max_*_len limits
default to the data length, so a bogus array32/map32 length is not
preallocated.
2026-09-29 14:06:40 +05:30
dependabot[bot] 1ede5ba84b build(deps): bump the actions group with 3 updates
Bumps the actions group with 3 updates: [korthout/backport-action](https://github.com/korthout/backport-action), [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `korthout/backport-action` from 4.6.0 to 4.6.1
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](https://github.com/korthout/backport-action/compare/2e830a1d0b8269505846ddd407a70876913ad1f8...6b65649031ac6d18ffdfd0c0820e9436f3fde22b)

Updates `github/codeql-action/init` from 4.38.1 to 4.38.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/1c5b675653bb5c22dbe9b12b556ec555138e09fd...2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2)

Updates `github/codeql-action/analyze` from 4.38.1 to 4.38.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/1c5b675653bb5c22dbe9b12b556ec555138e09fd...2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2)

---
updated-dependencies:
- dependency-name: korthout/backport-action
  dependency-version: 4.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-09-29 05:46:49 +00:00
dependabot[bot] 64c008dd07 build(deps-dev): bump the pip-dependencies group
Bumps the pip-dependencies group in /requirements.d with 4 updates: [build](https://github.com/pypa/build), [tox](https://github.com/tox-dev/tox), [coverage](https://github.com/coveragepy/coveragepy) and [pytest-benchmark](https://github.com/ionelmc/pytest-benchmark).


Updates `build` from 1.5.1 to 1.6.0
- [Release notes](https://github.com/pypa/build/releases)
- [Changelog](https://github.com/pypa/build/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pypa/build/compare/1.5.1...1.6.0)

Updates `tox` from 4.60.1 to 4.61.1
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.60.1...4.61.1)

Updates `coverage` from 7.15.4 to 7.16.0
- [Release notes](https://github.com/coveragepy/coveragepy/releases)
- [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst)
- [Commits](https://github.com/coveragepy/coveragepy/compare/7.15.4...7.16.0)

Updates `pytest-benchmark` from 5.2.3 to 5.3.0
- [Release notes](https://github.com/ionelmc/pytest-benchmark/releases)
- [Changelog](https://github.com/ionelmc/pytest-benchmark/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/ionelmc/pytest-benchmark/compare/v5.2.3...v5.3.0)

---
updated-dependencies:
- dependency-name: build
  dependency-version: 1.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: pip-dependencies
- dependency-name: tox
  dependency-version: 4.61.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: pip-dependencies
- dependency-name: coverage
  dependency-version: 7.16.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: pip-dependencies
- dependency-name: pytest-benchmark
  dependency-version: 5.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: pip-dependencies
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-09-29 05:43:26 +00:00
TW 09b2969d3f Merge pull request #10456 from ThomasWaldmann/legacy-remote-deque-10450
legacy remote: use deques for the RPC call queues, fixes #10450
2026-09-28 22:25:57 +02:00
Thomas WaldmannandClaude Opus 5.5 4897f7028f legacy remote: use deques for the RPC call queues, fixes #10450
LegacyRemoteRepository.call_many took the next call from the front of a
list (calls.pop(0)), which moves all the remaining entries each time.
get_many() passes all ids at once, so borg transfer --from-borg1
--chunker-params (which fetches all chunks of an item via fetch_many)
from a remote borg 1.x repository was quadratic in the chunk count of
the item.

Use collections.deque with popleft() for calls and waiting_for.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 20:33:33 +02:00
Mrityunjay Raj 774df94fc2 docs: update packs internals to match the current code
Correct what borg compact reclaims after a crash, how compact/repo-compress
rewrite index/, when the index is rebuilt from the packs and when the repair
walk is used. Add pack writer and read path docs.
2026-09-28 20:50:49 +05:30
TW b7015f32d5 Merge pull request #10448 from borgbackup/auto/update-fame
FAME.md: update contributor statistics
2026-09-28 15:08:10 +02:00
ThomasWaldmann 5f750e266d FAME.md: update contributor statistics 2026-09-28 04:34:46 +00:00
TW f1ca9f8325 Merge pull request #10444 from ThomasWaldmann/rel200b25
Release 2.0.0b25
2026-09-28 00:05:29 +02:00
Thomas Waldmann 82744708c0 update CHANGES 2.0.0b25 2026-09-27 23:02:37 +02:00
Thomas Waldmann 97f03619c7 build_usage build_man 2026-09-27 23:02:35 +02:00
Thomas WaldmannandClaude Opus 5.5 9e2e74f737 repo-create: avoid '*' in --id-hash help, fixes docutils warning
'authenticated-*' in the help text started an unterminated inline emphasis
in the generated rst usage docs and man page.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 23:01:45 +02:00
TW 64e6f2fda3 Merge pull request #10419 from mr-raj12/check-repair-salvage-pack-10026
repository: add salvage_pack, keeping only the authenticated objects of a corrupt pack, refs #10026
2026-09-27 22:39:24 +02:00
Mrityunjay Raj 296c9a018e repository: salvage_pack docstring and test fixes, refs #10026 2026-09-28 01:00:46 +05:30
Mrityunjay Raj 82c31cc2cb repository: salvage_pack catches only read failures, refs #10026
SALVAGE_READ_ERROR now covers OSError, BackendConnectionError and
ReadRangeError. Other store backend errors, e.g. BackendMustBeOpen,
PermissionDenied or QuotaExceeded, propagate.
2026-09-28 00:18:06 +05:30
Mrityunjay Raj 5d4f5f60f1 repository: salvage_pack review fixes, refs #10026 2026-09-27 19:52:33 +02:00
Mrityunjay Raj d7c71def62 repository: salvage_pack calls before_old_pack_delete only if the old pack is deleted, refs #10026 2026-09-27 19:52:07 +02:00
Mrityunjay Raj 943aef01a4 repository: add salvage_pack, keeping only the authenticated objects of a corrupt pack, refs #10026 2026-09-27 19:52:00 +02:00
TW a68d9434ce Merge pull request #10441 from ThomasWaldmann/repo-defaults-mandatory
repo-create: always write config/defaults, so its removal is detected, refs #346
2026-09-27 17:43:46 +02:00
Thomas WaldmannandClaude Fable 5.1 26ff43fdcc repo-create: always write config/defaults, so its removal is detected, refs #346
Without the object, the commands silently fell back to the built-in defaults, so
anybody with write access to the store could remove a repository default (e.g. an
"obfuscate" compression) unnoticed: the key protects the content of the object,
not its presence.

Now "borg repo-create" always writes config/defaults (empty if no default was
given), and a missing object is an error (Repository.DefaultsMissing, rc 34) like
one that fails the authentication: the commands using the defaults refuse to run.
"borg check" reports such an object, "borg check --repair" replaces it by empty
defaults, so the repository can be used again (with the built-in defaults).

with_repository reads the defaults only after the security checks (assert_secure).

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 17:09:59 +02:00
TW 57c0a6f349 Merge pull request #10440 from ThomasWaldmann/ci-cryptography-reinstall
CI: force-reinstall cryptography from source for the linux binaries
2026-09-27 17:07:00 +02:00
TW 6c1670437a Merge pull request #10442 from ThomasWaldmann/windows-repo-info-linesep
tests: use os.linesep in the repo-info default assertions
2026-09-27 17:06:35 +02:00
Thomas WaldmannandClaude Opus 5.5 e893f13ed1 tests: use os.linesep in the repo-info default assertions
On Windows, repo-info output lines end with CRLF, so the assertions
expecting a trailing "\n" failed there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 17:05:24 +02:00
Thomas WaldmannandClaude Opus 5.5 001b59cde5 CI: force-reinstall cryptography from source for the linux binaries
The moto S3 test server install already pulls in the cryptography
manylinux wheel, so a plain "pip install --no-binary cryptography"
kept that wheel (statically linked OpenSSL) and the dynamic libcrypto
check failed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 15:53:44 +02:00
TW bce686de68 Merge pull request #10439 from ThomasWaldmann/update-changes-master
update CHANGES
2026-09-27 15:27:01 +02:00
Thomas Waldmann 3e0acd9c9c update CHANGES 2026-09-27 15:19:58 +02:00
TW 88d0c42be9 Merge pull request #10438 from ThomasWaldmann/repo-default-compression
repo-create: store default compression and chunker params in the repository, fixes #346
2026-09-27 12:27:04 +02:00
Thomas WaldmannandClaude Opus 5.5 f694ba3e69 repo-create: store default compression and chunker params in the repository, fixes #346
"borg repo-create --compression SPEC --chunker-params PARAMS" stores repository
defaults in the new config/defaults store object.

Compression: the commands that compress data (create, recreate, import-tar,
transfer, repo-compress, debug put-obj) use the repository default if no
compression was given via the command line, the environment or default.yaml;
without a repository default, they use lz4 as before.

Chunker params: "--chunker-params default" now means the repository default,
else the built-in CHUNKER_PARAMS: ChunkerParams("default") returns the
DEFAULT_CHUNKER_PARAMS marker and with_repository replaces it by the real
chunker params. borg create and borg import-tar use the marker as their parser
default, so they use the repository default if no chunker params were given.
borg recreate and borg transfer still only rechunk if --chunker-params is
given; with "default", they rechunk to the repository default.

config/defaults is stored in the key's store object envelope, so it is
authenticated: nobody without the key can change the defaults (e.g. remove an
"obfuscate" compression) without being noticed. config/config can not hold
them, as it is read before the key is known and is not authenticated.
config/defaults is read at most once per Repository object.

borg repo-info shows the defaults (also in --json).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 03:41:25 +02:00
TW 69f7bb23d8 Merge pull request #10437 from ThomasWaldmann/repo-list-missing-archive-10435
repo-list, compact: handle archives with a missing metadata object, fixes #10435
2026-09-27 01:40:48 +02:00
Thomas WaldmannandClaude Opus 5.5 9b3b7eb819 repo-list, compact: handle archives with a missing metadata object, fixes #10435
If an archive's metadata object is missing or invalid while its archives/ entry
still exists, Archives.list() yields a placeholder ArchiveInfo for it, but
opening it as an Archive raises Archive.DoesNotExist.

- ArchiveFormatter: use the placeholder values of the ArchiveInfo (and defaults)
  if the archive can not be opened, so repo-list (and prune --list) go on.
- compact: skip such a soft-deleted archive with the "cannot be fully preserved"
  warning, as documented in mark_soft_deleted_used(), instead of aborting.
- Archive.DoesNotExist: show a binary archive id as hex.
- check --format: keep using the fallback format for such archives.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 00:18:47 +02:00
TW e6803d2815 Merge pull request #10432 from ThomasWaldmann/tag-append-10430
tag options: one tag per option, fixes #10430
2026-09-27 00:08:59 +02:00
Thomas WaldmannandClaude Fable 5.1 cce5c99f4f tag: only rewrite the archive metadata if the tags changed
Previously, "borg tag" always rewrote the archive metadata (and thus the
archive entry in the repository), even when just listing the tags or when
the requested change was a no-op (including a refused --set).

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-26 23:19:51 +02:00
Thomas WaldmannandClaude Opus 5.5 7ecf12df2b docs: explain the tags: archive match pattern
Document that tags: takes a comma-separated list of tags and matches
archives having all of them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 23:19:46 +02:00
Thomas WaldmannandClaude Opus 5.5 d76a58b729 tag: warn if --set is refused because it would remove special tags
Previously, borg silently did not set the tags, so it looked like the
given tags were just ignored, and the return code was 0.

Now borg emits a warning naming the special tags that would be removed
and exits with rc 1 (warning).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 23:19:43 +02:00
Thomas WaldmannandClaude Opus 5.5 2c058d1d89 tag: refuse to change the tags of all archives without a selection
Without NAME or archive filter options, "borg tag --set/--clear/--add/--remove"
silently changed the tags of all archives in the repository.

Now it aborts like "borg delete" does, unless archives are selected
explicitly, e.g. using -a 'sh:*' for all archives. Just showing the
tags of all archives still works without a selection.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 23:19:41 +02:00
Thomas WaldmannandClaude Opus 5.5 83b6583dd7 create: replace --tags with --tag, taking one tag per option
--tags used nargs="+" and thus swallowed the archive NAME if it was given
after it, e.g. "borg create --tags foo NAME PATH" failed.

Now --tag takes exactly one tag and can be given multiple times,
e.g. "borg create --tag foo --tag bar NAME PATH".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 23:19:38 +02:00