diff --git a/src/borg/helpers/__init__.py b/src/borg/helpers/__init__.py index 0f4f98e51..82364613d 100644 --- a/src/borg/helpers/__init__.py +++ b/src/borg/helpers/__init__.py @@ -25,7 +25,7 @@ from .fs import O_, flags_dir, flags_special_follow, flags_special, flags_base, from .fs import HardLinkManager from .misc import sysinfo, log_multi, consume from .misc import ChunkIteratorFileWrapper, open_item, chunkit, iter_separated, ErrorIgnoringTextIOWrapper -from .parseformat import bin_to_hex, safe_encode, safe_decode +from .parseformat import bin_to_hex, hex_to_bin, safe_encode, safe_decode from .parseformat import text_to_json, binary_to_json, remove_surrogates, join_cmd from .parseformat import eval_escapes, decode_dict, positive_int_validator, interval from .parseformat import PathSpec, SortBySpec, ChunkerParams, FilesCacheMode, partial_format, DatetimeWrapper diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index e5752d34a..c82769730 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -1,6 +1,7 @@ import abc import argparse import base64 +import binascii import hashlib import json import os @@ -10,7 +11,6 @@ import shlex import stat import uuid from typing import Dict, Set, Tuple, ClassVar, Any, TYPE_CHECKING, Literal -from binascii import hexlify from collections import Counter, OrderedDict from datetime import datetime, timezone from functools import partial @@ -33,7 +33,18 @@ if TYPE_CHECKING: def bin_to_hex(binary): - return hexlify(binary).decode("ascii") + return binascii.hexlify(binary).decode("ascii") + + +def hex_to_bin(hex, length=None): + try: + binary = binascii.unhexlify(hex) + binary_len = len(binary) + if length is not None and binary_len != length: + raise ValueError(f"Expected {length} bytes ({2 * length} hex digits), got {binary_len} bytes.") + except binascii.Error as e: + raise ValueError(str(e)) from None + return binary def safe_decode(s, coding="utf-8", errors="surrogateescape"): diff --git a/src/borg/remote.py b/src/borg/remote.py index 5d9cb1af9..0aa636220 100644 --- a/src/borg/remote.py +++ b/src/borg/remote.py @@ -21,7 +21,7 @@ import borg.logger from . import __version__ from .compress import Compressor from .constants import * # NOQA -from .helpers import Error, IntegrityError +from .helpers import Error, ErrorWithTraceback, IntegrityError from .helpers import bin_to_hex from .helpers import get_limited_unpacker from .helpers import replace_placeholders @@ -766,7 +766,11 @@ class RemoteRepository: error = unpacked["exception_class"] args = unpacked["exception_args"] - if error == "DoesNotExist": + if error == "Error": + raise Error(args[0]) + elif error == "ErrorWithTraceback": + raise ErrorWithTraceback(args[0]) + elif error == "DoesNotExist": raise Repository.DoesNotExist(self.location.processed) elif error == "AlreadyExists": raise Repository.AlreadyExists(self.location.processed)