diff --git a/src/borg/archive.py b/src/borg/archive.py index dcc85deef..f381d1c71 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -1277,12 +1277,16 @@ class FilesystemObjectProcessors: def create_helper(self, path, st, status=None, hardlinkable=True, strip_prefix=None): if strip_prefix is not None: assert not path.endswith("/") - if strip_prefix.startswith(path + "/"): + if path + "/" == strip_prefix: + # this is the directory the slashdot hack points to - archive it as the root. + path = "." + elif strip_prefix.startswith(path + "/"): # still on a directory level that shall be stripped - do not create an item for this! yield None, "x", False, None return - # adjust path, remove stripped directory levels - path = path.removeprefix(strip_prefix) + else: + # adjust path, remove stripped directory levels + path = path.removeprefix(strip_prefix) sanitized_path = remove_dotdot_prefixes(path) item = Item(path=sanitized_path) diff --git a/src/borg/testsuite/archiver/create_cmd_test.py b/src/borg/testsuite/archiver/create_cmd_test.py index 498e02e89..b292bd0ff 100644 --- a/src/borg/testsuite/archiver/create_cmd_test.py +++ b/src/borg/testsuite/archiver/create_cmd_test.py @@ -1002,6 +1002,25 @@ def test_create_dotslash_hack(archivers, request): assert "secondB/thirdB" in output +def test_create_dotslash_hack_root_metadata(archivers, request): + """Test that the slashdot hack archives the source directory metadata as the archive root.""" + archiver = request.getfixturevalue(archivers) + os.makedirs(os.path.join(archiver.input_path, "first", "subdir")) + create_regular_file(archiver.input_path, "first/file1", contents=b"hello") + cmd(archiver, "repo-create", RK_ENCRYPTION) + cmd(archiver, "create", "test", "input/first/./") # slashdot hack + output = cmd(archiver, "list", "test") + # the root directory "." must be in the archive (this was the bug in #9534). + lines = output.splitlines() + assert lines[0].endswith(" .") + # children of the slashdot target must be archived. + assert "subdir" in output + assert "file1" in output + # parent directories must NOT be in the archive. + assert "input" not in output + assert "first" not in output + + def test_log_json(archivers, request): archiver = request.getfixturevalue(archivers) create_test_files(archiver.input_path)