Skip to content

Commit

Permalink
Merge pull request #8463 from ThomasWaldmann/borgfs-dir-names
Browse files Browse the repository at this point in the history
mount: create unique directory names, fixes #8461
  • Loading branch information
ThomasWaldmann authored Oct 5, 2024
2 parents 91c0def + f624f76 commit c5e48c7
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
14 changes: 10 additions & 4 deletions src/borg/fuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import sys
import tempfile
import time
from collections import defaultdict
from collections import defaultdict, Counter
from signal import SIGINT

from .constants import ROBJ_FILE_STREAM
Expand Down Expand Up @@ -39,7 +39,7 @@ def async_wrapper(fn):
from .archiver._common import build_matcher, build_filter
from .archive import Archive, get_item_uid_gid
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 msgpack
from .helpers.lrucache import LRUCache
Expand Down Expand Up @@ -277,14 +277,20 @@ def __init__(self, manifest, args, decrypted_repository):
def _create_filesystem(self):
self._create_dir(parent=1) # first call, create root dir (inode == 1)
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:
# process archives immediately
self._process_archive(archive.id)
else:
# lazily load archives, create archive placeholder inode
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

def get_item(self, inode):
Expand Down
18 changes: 18 additions & 0 deletions src/borg/testsuite/archiver/mount_cmds_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,24 @@ def test_fuse_versions_view(archivers, request):
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")
def test_fuse_allow_damaged_files(archivers, request):
archiver = request.getfixturevalue(archivers)
Expand Down

0 comments on commit c5e48c7

Please sign in to comment.