Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/borg/archiver/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
from ..helpers.nanorst import rst_to_terminal
from ..manifest import Manifest, AI_HUMAN_SORT_KEYS
from ..patterns import PatternMatcher
from ..legacyremote import LegacyRemoteRepository
from ..legacy.remote import LegacyRemoteRepository
from ..remote import RemoteRepository
from ..legacyrepository import LegacyRepository
from ..legacy.repository import LegacyRepository
from ..repository import Repository
from ..repoobj import RepoObj, RepoObj1
from ..repoobj import RepoObj
from ..legacy.repoobj import RepoObj1
from ..patterns import (
ArgparsePatternAction,
ArgparseExcludeFileAction,
Expand Down
2 changes: 1 addition & 1 deletion src/borg/archiver/transfer_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from ..helpers.argparsing import ArgumentParser, ArgumentTypeError
from ..item import ChunkListEntry
from ..manifest import Manifest
from ..legacyrepository import LegacyRepository
from ..legacy.repository import LegacyRepository
from ..repository import Repository

from ..logger import create_logger
Expand Down
2 changes: 1 addition & 1 deletion src/borg/helpers/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def safe_unlink(path):
Use this when deleting potentially large files when recovering
from a VFS error such as ENOSPC. It can help a full file system
recover. Refer to the "File system interaction" section
in legacyrepository.py for further explanations.
in legacy/repository.py for further explanations.
"""
path_obj = Path(path)
try:
Expand Down
4 changes: 2 additions & 2 deletions src/borg/helpers/parseformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -1335,9 +1335,9 @@ def ellipsis_truncate(msg, space):

class BorgJsonEncoder(json.JSONEncoder):
def default(self, o):
from ..legacyrepository import LegacyRepository
from ..legacy.repository import LegacyRepository
from ..repository import Repository
from ..legacyremote import LegacyRemoteRepository
from ..legacy.remote import LegacyRemoteRepository
from ..remote import RemoteRepository
from ..archive import Archive
from ..cache import AdHocWithFilesCache
Expand Down
8 changes: 8 additions & 0 deletions src/borg/legacy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
Borg Legacy Package — Borg 1.x compatibility layer.
This package contains all code specific to reading/writing Borg 1.x repositories.
It is required for ``borg transfer --from-borg1`` and ``borg serve`` (serving v1 clients).
This package can be removed entirely when Borg 1.x support is dropped.
"""
36 changes: 18 additions & 18 deletions src/borg/legacyremote.py → src/borg/legacy/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@

from xxhash import xxh64

from . import __version__
from .compress import Compressor
from .constants import * # NOQA
from .helpers import Error, ErrorWithTraceback, IntegrityError
from .helpers import bin_to_hex
from .helpers import get_limited_unpacker
from .helpers import replace_placeholders
from .helpers import format_file_size
from .helpers import safe_unlink
from .helpers import prepare_subprocess_env, ignore_sigint
from .helpers import get_socket_filename
from .fslocking import LockTimeout, NotLocked, NotMyLock, LockFailed
from .logger import create_logger
from .helpers import msgpack
from .legacyrepository import LegacyRepository
from .version import parse_version, format_version
from .helpers.datastruct import EfficientCollectionQueue
from .platform import is_win32
from .. import __version__
from ..compress import Compressor
from ..constants import * # NOQA
from ..helpers import Error, ErrorWithTraceback, IntegrityError
from ..helpers import bin_to_hex
from ..helpers import get_limited_unpacker
from ..helpers import replace_placeholders
from ..helpers import format_file_size
from ..helpers import safe_unlink
from ..helpers import prepare_subprocess_env, ignore_sigint
from ..helpers import get_socket_filename
from ..fslocking import LockTimeout, NotLocked, NotMyLock, LockFailed
from ..logger import create_logger
from ..helpers import msgpack
from .repository import LegacyRepository
from ..version import parse_version, format_version
from ..helpers.datastruct import EfficientCollectionQueue
from ..platform import is_win32

logger = create_logger(__name__)

Expand Down
75 changes: 75 additions & 0 deletions src/borg/legacy/repoobj.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Legacy RepoObj1 — Borg 1.x repository object format.

Moved from borg.repoobj as part of the legacy code separation.
"""

from ..constants import * # NOQA
from ..helpers import workarounds
from ..compress import Compressor, get_compressor

# Workaround for lost passphrase or key in "authenticated" or "authenticated-blake2" mode
AUTHENTICATED_NO_KEY = "authenticated_no_key" in workarounds


class RepoObj1: # legacy
@classmethod
def extract_crypted_data(cls, data: bytes) -> bytes:
# used for crypto type detection
return data

def __init__(self, key):
self.key = key
self.compressor = get_compressor("lz4", legacy_mode=True)

def id_hash(self, data: bytes) -> bytes:
return self.key.id_hash(data)

def format(
self,
id: bytes,
meta: dict,
data: bytes,
compress: bool = True,
size: int = None,
ctype: int = None,
clevel: int = None,
ro_type: str = None,
) -> bytes:
assert isinstance(id, bytes)
assert meta == {}
assert isinstance(data, (bytes, memoryview))
assert ro_type is not None
assert compress or size is not None and ctype is not None and clevel is not None
if compress:
assert size is None or size == len(data)
meta, data_compressed = self.compressor.compress(meta, data)
else:
assert isinstance(size, int)
data_compressed = data # is already compressed, must include type/level bytes
data_encrypted = self.key.encrypt(id, data_compressed)
return data_encrypted

def parse_meta(self, id: bytes, cdata: bytes) -> dict:
raise NotImplementedError("parse_meta is not available for RepoObj1")

def parse(
self, id: bytes, cdata: bytes, decompress: bool = True, want_compressed: bool = False, ro_type: str = None
) -> tuple[dict, bytes]:
assert not (not decompress and not want_compressed), "invalid parameter combination!"
assert isinstance(id, bytes)
assert isinstance(cdata, bytes)
assert ro_type is not None
data_compressed = self.key.decrypt(id, cdata)
compressor_cls, compression_level = Compressor.detect(data_compressed[:2])
compressor = compressor_cls(level=compression_level, legacy_mode=True)
meta_compressed = {}
meta_compressed["ctype"] = compressor.ID
meta_compressed["clevel"] = compressor.level
meta_compressed["csize"] = len(data_compressed)
if decompress:
meta, data = compressor.decompress(None, data_compressed)
if not AUTHENTICATED_NO_KEY:
self.key.assert_id(id, data)
else:
meta, data = None, None
return meta_compressed if want_compressed else meta, data_compressed if want_compressed else data
32 changes: 16 additions & 16 deletions src/borg/legacyrepository.py → src/borg/legacy/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@

import xxhash

from .constants import * # NOQA
from .hashindex import NSIndex1Entry, NSIndex1
from .helpers import Error, ErrorWithTraceback, IntegrityError, format_file_size, parse_file_size
from .helpers import Location
from .helpers import ProgressIndicatorPercent
from .helpers import bin_to_hex, hex_to_bin
from .helpers import secure_erase, safe_unlink
from .helpers import msgpack
from .helpers.lrucache import LRUCache
from .fslocking import Lock, LockError, LockErrorT
from .logger import create_logger
from .manifest import Manifest, NoManifestError
from .platform import SaveFile, SyncFile, sync_dir, safe_fadvise
from .repoobj import RepoObj
from .checksums import crc32
from .crypto.file_integrity import IntegrityCheckedFile, FileIntegrityError
from ..constants import * # NOQA
from ..hashindex import NSIndex1Entry, NSIndex1
from ..helpers import Error, ErrorWithTraceback, IntegrityError, format_file_size, parse_file_size
from ..helpers import Location
from ..helpers import ProgressIndicatorPercent
from ..helpers import bin_to_hex, hex_to_bin
from ..helpers import secure_erase, safe_unlink
from ..helpers import msgpack
from ..helpers.lrucache import LRUCache
from ..fslocking import Lock, LockError, LockErrorT
from ..logger import create_logger
from ..manifest import Manifest, NoManifestError
from ..platform import SaveFile, SyncFile, sync_dir, safe_fadvise
from ..repoobj import RepoObj
from ..checksums import crc32
from ..crypto.file_integrity import IntegrityCheckedFile, FileIntegrityError

logger = create_logger(__name__)

Expand Down
2 changes: 1 addition & 1 deletion src/borg/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def ids(self, *, deleted=False):

def _get_archive_meta(self, id: bytes) -> dict:
# get all metadata directly from the ArchiveItem in the repo.
from .legacyrepository import LegacyRepository
from .legacy.repository import LegacyRepository
from .repository import Repository

try:
Expand Down
2 changes: 1 addition & 1 deletion src/borg/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from .logger import create_logger, borg_serve_log_queue
from .manifest import NoManifestError
from .helpers import msgpack
from .legacyrepository import LegacyRepository
from .legacy.repository import LegacyRepository
from .repository import Repository, StoreObjectNotFound
from .version import parse_version, format_version
from .helpers.datastruct import EfficientCollectionQueue
Expand Down
66 changes: 3 additions & 63 deletions src/borg/repoobj.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .constants import * # NOQA
from .helpers import msgpack, workarounds
from .helpers.errors import IntegrityError
from .compress import Compressor, LZ4_COMPRESSOR, get_compressor
from .compress import Compressor, LZ4_COMPRESSOR

# Workaround for lost passphrase or key in "authenticated" or "authenticated-blake2" mode
AUTHENTICATED_NO_KEY = "authenticated_no_key" in workarounds
Expand Down Expand Up @@ -139,65 +139,5 @@ def parse(
return meta_compressed if want_compressed else meta, data_compressed if want_compressed else data


class RepoObj1: # legacy
@classmethod
def extract_crypted_data(cls, data: bytes) -> bytes:
# used for crypto type detection
return data

def __init__(self, key):
self.key = key
self.compressor = get_compressor("lz4", legacy_mode=True)

def id_hash(self, data: bytes) -> bytes:
return self.key.id_hash(data)

def format(
self,
id: bytes,
meta: dict,
data: bytes,
compress: bool = True,
size: int = None,
ctype: int = None,
clevel: int = None,
ro_type: str = None,
) -> bytes:
assert isinstance(id, bytes)
assert meta == {}
assert isinstance(data, (bytes, memoryview))
assert ro_type is not None
assert compress or size is not None and ctype is not None and clevel is not None
if compress:
assert size is None or size == len(data)
meta, data_compressed = self.compressor.compress(meta, data)
else:
assert isinstance(size, int)
data_compressed = data # is already compressed, must include type/level bytes
data_encrypted = self.key.encrypt(id, data_compressed)
return data_encrypted

def parse_meta(self, id: bytes, cdata: bytes) -> dict:
raise NotImplementedError("parse_meta is not available for RepoObj1")

def parse(
self, id: bytes, cdata: bytes, decompress: bool = True, want_compressed: bool = False, ro_type: str = None
) -> tuple[dict, bytes]:
assert not (not decompress and not want_compressed), "invalid parameter combination!"
assert isinstance(id, bytes)
assert isinstance(cdata, bytes)
assert ro_type is not None
data_compressed = self.key.decrypt(id, cdata)
compressor_cls, compression_level = Compressor.detect(data_compressed[:2])
compressor = compressor_cls(level=compression_level, legacy_mode=True)
meta_compressed = {}
meta_compressed["ctype"] = compressor.ID
meta_compressed["clevel"] = compressor.level
meta_compressed["csize"] = len(data_compressed)
if decompress:
meta, data = compressor.decompress(None, data_compressed)
if not AUTHENTICATED_NO_KEY:
self.key.assert_id(id, data)
else:
meta, data = None, None
return meta_compressed if want_compressed else meta, data_compressed if want_compressed else data
# Backward compatibility: RepoObj1 has moved to borg.legacy.repoobj
from .legacy.repoobj import RepoObj1 # noqa: F401
8 changes: 4 additions & 4 deletions src/borg/testsuite/legacyrepository_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
from ..helpers import msgpack
from ..fslocking import Lock, LockFailed
from ..platformflags import is_win32
from ..legacyremote import LegacyRemoteRepository, InvalidRPCMethod, PathNotAllowed
from ..legacyrepository import LegacyRepository, LoggedIO
from ..legacyrepository import MAGIC, MAX_DATA_SIZE, TAG_DELETE, TAG_PUT2, TAG_PUT, TAG_COMMIT
from ..legacy.remote import LegacyRemoteRepository, InvalidRPCMethod, PathNotAllowed
from ..legacy.repository import LegacyRepository, LoggedIO
from ..legacy.repository import MAGIC, MAX_DATA_SIZE, TAG_DELETE, TAG_PUT2, TAG_PUT, TAG_COMMIT
from ..repoobj import RepoObj
from .hashindex_test import H

Expand Down Expand Up @@ -664,7 +664,7 @@ def test_subtly_corrupted_hints_without_integrity(repository, caplog):
repository.put(H(3), fchunk(b"1234"))
# Do a compaction run.
# The corrupted refcount is detected and logged as a warning, but compaction proceeds.
caplog.set_level(logging.WARNING, logger="borg.legacyrepository")
caplog.set_level(logging.WARNING, logger="borg.legacy.repository")
repository.commit(compact=True)
assert "Corrupted segment reference count" in caplog.text
# We verify that the repository is still consistent.
Expand Down
3 changes: 2 additions & 1 deletion src/borg/testsuite/repoobj_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from ..crypto.key import PlaintextKey
from ..helpers.errors import IntegrityError
from ..repository import Repository
from ..repoobj import RepoObj, RepoObj1
from ..repoobj import RepoObj
from ..legacy.repoobj import RepoObj1
from ..compress import LZ4


Expand Down
Loading