diff --git a/borg/helpers.py b/borg/helpers.py index b342c60e0..15c01bb7c 100644 --- a/borg/helpers.py +++ b/borg/helpers.py @@ -681,11 +681,15 @@ def posix_acl_use_stored_uid_gid(acl): def safe_decode(s, coding='utf-8', errors='surrogateescape'): """decode bytes to str, with round-tripping "invalid" bytes""" + if s is None: + return None return s.decode(coding, errors) def safe_encode(s, coding='utf-8', errors='surrogateescape'): """encode str to bytes, with round-tripping "invalid" bytes""" + if s is None: + return None return s.encode(coding, errors) diff --git a/borg/item.py b/borg/item.py index 2bf9c650b..b0cbf12a3 100644 --- a/borg/item.py +++ b/borg/item.py @@ -1,5 +1,5 @@ from .constants import ITEM_KEYS -from .helpers import safe_encode, safe_decode, StableDict +from .helpers import safe_encode, safe_decode, bigint_to_int, int_to_bigint, StableDict class PropDict: @@ -112,22 +112,24 @@ class Item(PropDict): path = PropDict._make_property('path', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) source = PropDict._make_property('source', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) - user = PropDict._make_property('user', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) - group = PropDict._make_property('group', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) acl_access = PropDict._make_property('acl_access', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) acl_default = PropDict._make_property('acl_default', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) acl_extended = PropDict._make_property('acl_extended', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) acl_nfs4 = PropDict._make_property('acl_nfs4', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) + user = PropDict._make_property('user', (str, type(None)), 'surrogate-escaped str or None', encode=safe_encode, decode=safe_decode) + group = PropDict._make_property('group', (str, type(None)), 'surrogate-escaped str or None', encode=safe_encode, decode=safe_decode) + mode = PropDict._make_property('mode', int) uid = PropDict._make_property('uid', int) gid = PropDict._make_property('gid', int) - atime = PropDict._make_property('atime', int) - ctime = PropDict._make_property('ctime', int) - mtime = PropDict._make_property('mtime', int) rdev = PropDict._make_property('rdev', int) bsdflags = PropDict._make_property('bsdflags', int) + atime = PropDict._make_property('atime', int, 'bigint', encode=int_to_bigint, decode=bigint_to_int) + ctime = PropDict._make_property('ctime', int, 'bigint', encode=int_to_bigint, decode=bigint_to_int) + mtime = PropDict._make_property('mtime', int, 'bigint', encode=int_to_bigint, decode=bigint_to_int) + hardlink_master = PropDict._make_property('hardlink_master', bool) chunks = PropDict._make_property('chunks', list) diff --git a/borg/testsuite/item.py b/borg/testsuite/item.py index e41d6ae18..16e887cbb 100644 --- a/borg/testsuite/item.py +++ b/borg/testsuite/item.py @@ -63,6 +63,25 @@ def test_item_int_property(): item.mode = "invalid" +def test_item_bigint_property(): + item = Item() + small, big = 42, 2 ** 65 + item.atime = small + assert item.atime == small + assert item.as_dict() == {'atime': small} + item.atime = big + assert item.atime == big + assert item.as_dict() == {'atime': b'\0' * 8 + b'\x02'} + + +def test_item_user_group_none(): + item = Item() + item.user = None + assert item.user is None + item.group = None + assert item.group is None + + def test_item_se_str_property(): # start simple item = Item()