From 30194fb64f747c0b78900149687d78c213f08b8c Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 18 Aug 2026 16:19:09 +0200 Subject: [PATCH] import-tar: fix nfiles being counted twice for regular files _import_tar incremented archive.stats.nfiles for every regular tar member, but TarfileObjectProcessors.process_file already counts those in tfo.stats (and process_hardlink counts hardlink members). Since archive.stats += tfo.stats is added before archive.save(), imported archives persisted nfiles = 2 * regular_files + hardlinks. Remove the redundant increment (borg create also relies solely on the processor-side accounting) and add a test asserting that the archive metadata nfiles equals regular files + hardlink members after borg import-tar. Co-Authored-By: Claude Fable 5 --- src/borg/archiver/tar_cmds.py | 1 - src/borg/testsuite/archiver/tar_cmds_test.py | 29 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/borg/archiver/tar_cmds.py b/src/borg/archiver/tar_cmds.py index 18fd8f3feb..51594c43d6 100644 --- a/src/borg/archiver/tar_cmds.py +++ b/src/borg/archiver/tar_cmds.py @@ -569,7 +569,6 @@ def _import_tar(self, args, repository, manifest, key, cache, tarstream): while tarinfo := tar.next(): if tarinfo.isreg(): status = tfo.process_file(tarinfo=tarinfo, status="A", type=stat.S_IFREG, tar=tar) - archive.stats.nfiles += 1 elif tarinfo.isdir(): status = tfo.process_dir(tarinfo=tarinfo, status="d", type=stat.S_IFDIR) elif tarinfo.issym(): diff --git a/src/borg/testsuite/archiver/tar_cmds_test.py b/src/borg/testsuite/archiver/tar_cmds_test.py index 5a1ea8f4fb..0888f944fd 100644 --- a/src/borg/testsuite/archiver/tar_cmds_test.py +++ b/src/borg/testsuite/archiver/tar_cmds_test.py @@ -1,3 +1,5 @@ +import io +import json import os import random import shutil @@ -125,6 +127,33 @@ def test_import_tar(archivers, request, tar_format="PAX"): assert_dirs_equal("input", "output/input", ignore_ns=True, ignore_xattrs=True) +def test_import_tar_nfiles(archivers, request): + archiver = request.getfixturevalue(archivers) + # Build a tar with 2 regular files, 1 hardlink, 1 directory and 1 symlink. + with tarfile.open("input.tar", "w") as tar: + for name in ("dir/file1", "dir/file2"): + data = name.encode() + tarinfo = tarfile.TarInfo(name) + tarinfo.size = len(data) + tar.addfile(tarinfo, io.BytesIO(data)) + tarinfo = tarfile.TarInfo("dir/hardlink1") + tarinfo.type = tarfile.LNKTYPE + tarinfo.linkname = "dir/file1" + tar.addfile(tarinfo) + tarinfo = tarfile.TarInfo("dir/subdir") + tarinfo.type = tarfile.DIRTYPE + tar.addfile(tarinfo) + tarinfo = tarfile.TarInfo("dir/symlink1") + tarinfo.type = tarfile.SYMTYPE + tarinfo.linkname = "file1" + tar.addfile(tarinfo) + cmd(archiver, "repo-create", "--encryption=none-sha256") + cmd(archiver, "import-tar", "dst", "input.tar") + info = json.loads(cmd(archiver, "info", "--json", "dst")) + # as with borg create, each regular file and each hardlink counts, directories/symlinks do not + assert info["archives"][0]["stats"]["nfiles"] == 3 + + def test_import_unusual_tar(archivers, request): archiver = request.getfixturevalue(archivers)