Repository navigation
extract: skip a hard link item that refers to itself, refs #10393 (1.4-maint) - #10599
Merged
ThomasWaldmann merged 1 commit intoNov 5, 2026
Conversation
…#10393 If an archive has the same hard link item twice (e.g. a recursion root inside an earlier root, or the same path given twice via --paths-from-stdin) and the item's path is the link target of its hard link group, extract removed the already extracted file and then failed to hard link the path to itself. The file (and its other hard links) was missing afterwards. Such a duplicate item is skipped now, its path was extracted already. This also makes existing archives with such duplicates restore correctly. export-tar and mount skip it likewise: export-tar added a hard link entry pointing to itself (bsdtar refuses it and exits with rc 1), mount counted it as an additional link (st_nlink one too high). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
An archive can contain the same hard link item twice. Two ways to get one:
borg create ::a input input/file3, whereinput/file3is a hard link and the first member of its hard link group. The rootinput/file3lies inside the earlier rootinput.printf 'input/file1\ninput/file1\n' | borg create --paths-from-stdin ::awith a hard-linkedinput/file1. This is deterministic.The duplicate is an
hitem whosesourceis its own path:borg extractfirst extractsinput/file1. For the duplicate, the "remove existing files" step then unlinks that file, and hard linking the path to itself fails with ENOENT. Extract returns rc 1, andinput/file1is gone, along with its other hard links (input/file2fails to link the same way), although the archive data is intact:Fix: extract now skips a hard link item whose link target is its own path. That path was extracted already. The check runs before anything touches the filesystem. It uses the same link target that
extract_helperwould use (hardlink_mastersand--strip-componentstaken into account). This is the extract-side part of #10394 (master), ported to 1.4'ssource/hardlink_mastershard link model. Because it works on the items as they are stored, it also makes existing archives that contain such duplicates restore correctly.export-tarandmountget the same small guard:export-tarwrote aLNKTYPEentry that links to itself. GNU tar and Python's tarfile ignore it, but bsdtar (libarchive) says "Skipping hardlink pointing to itself" and exits with rc 1.mountcounted the duplicate as another link, sost_nlinkwas one too high (3 instead of 2). Contents were fine.The create side (not archiving such duplicates in the first place) is not part of this PR.
refs #10393
Checklist
1.4-mainttest_extract_duplicate_hardlink_item(also with--strip-components),test_export_tar_duplicate_hardlink_item,test_fuse_mount_duplicate_hardlink_item. The extract and export-tar tests fail without the fix.archiver.pyandarchive.pytest modules pass locally (macOS). The FUSE tests, including the new one, pass on Linux with pyfuse3.🤖 Generated with Claude Code