1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2025-01-01 12:45:34 +00:00

Merge pull request #8463 from ThomasWaldmann/borgfs-dir-names

mount: create unique directory names, fixes #8461
This commit is contained in:
TW 2024-10-05 23:59:51 +02:00 committed by GitHub
commit c5e48c700b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 28 additions and 4 deletions

View file

@ -7,7 +7,7 @@
import sys import sys
import tempfile import tempfile
import time import time
from collections import defaultdict from collections import defaultdict, Counter
from signal import SIGINT from signal import SIGINT
from .constants import ROBJ_FILE_STREAM from .constants import ROBJ_FILE_STREAM
@ -39,7 +39,7 @@ def async_wrapper(fn):
from .archiver._common import build_matcher, build_filter from .archiver._common import build_matcher, build_filter
from .archive import Archive, get_item_uid_gid from .archive import Archive, get_item_uid_gid
from .hashindex import FuseVersionsIndex from .hashindex import FuseVersionsIndex
from .helpers import daemonize, daemonizing, signal_handler, format_file_size from .helpers import daemonize, daemonizing, signal_handler, format_file_size, bin_to_hex
from .helpers import HardLinkManager from .helpers import HardLinkManager
from .helpers import msgpack from .helpers import msgpack
from .helpers.lrucache import LRUCache from .helpers.lrucache import LRUCache
@ -277,14 +277,20 @@ def __init__(self, manifest, args, decrypted_repository):
def _create_filesystem(self): def _create_filesystem(self):
self._create_dir(parent=1) # first call, create root dir (inode == 1) self._create_dir(parent=1) # first call, create root dir (inode == 1)
self.versions_index = FuseVersionsIndex() self.versions_index = FuseVersionsIndex()
for archive in self._manifest.archives.list_considering(self._args): archives = self._manifest.archives.list_considering(self._args)
name_counter = Counter(a.name for a in archives)
duplicate_names = {a.name for a in archives if name_counter[a.name] > 1}
for archive in archives:
if self.versions: if self.versions:
# process archives immediately # process archives immediately
self._process_archive(archive.id) self._process_archive(archive.id)
else: else:
# lazily load archives, create archive placeholder inode # lazily load archives, create archive placeholder inode
archive_inode = self._create_dir(parent=1, mtime=int(archive.ts.timestamp() * 1e9)) archive_inode = self._create_dir(parent=1, mtime=int(archive.ts.timestamp() * 1e9))
self.contents[1][os.fsencode(archive.name)] = archive_inode name = f"{archive.name}"
if name in duplicate_names:
name += f"-{bin_to_hex(archive.id):.8}"
self.contents[1][os.fsencode(name)] = archive_inode
self.pending_archives[archive_inode] = archive self.pending_archives[archive_inode] = archive
def get_item(self, inode): def get_item(self, inode):

View file

@ -200,6 +200,24 @@ def test_fuse_versions_view(archivers, request):
assert open(hl3, "rb").read() == b"123456" assert open(hl3, "rb").read() == b"123456"
@pytest.mark.skipif(not llfuse, reason="llfuse not installed")
def test_fuse_duplicate_name(archivers, request):
archiver = request.getfixturevalue(archivers)
cmd(archiver, "repo-create", RK_ENCRYPTION)
cmd(archiver, "create", "duplicate", "input")
cmd(archiver, "create", "duplicate", "input")
cmd(archiver, "create", "unique1", "input")
cmd(archiver, "create", "unique2", "input")
mountpoint = os.path.join(archiver.tmpdir, "mountpoint")
# mount the whole repository, archives show up as toplevel directories:
with fuse_mount(archiver, mountpoint):
path = os.path.join(mountpoint)
dirs = os.listdir(path)
assert len(set(dirs)) == 4 # there must be 4 unique dir names for 4 archives
assert "unique1" in dirs # if an archive has a unique name, do not append the archive id
assert "unique2" in dirs
@pytest.mark.skipif(not llfuse, reason="llfuse not installed") @pytest.mark.skipif(not llfuse, reason="llfuse not installed")
def test_fuse_allow_damaged_files(archivers, request): def test_fuse_allow_damaged_files(archivers, request):
archiver = request.getfixturevalue(archivers) archiver = request.getfixturevalue(archivers)