mirror of https://github.com/borgbackup/borg.git
xattr: implement set_all to complement get_all
also: follow_symlinks param defaults to False (we do never use True) fix tests, xattrs are set via FD now.
This commit is contained in:
parent
c29c3063b0
commit
394d59e6d8
|
@ -1,4 +1,3 @@
|
|||
import errno
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
|
@ -674,7 +673,6 @@ Utilization of max. archive size: {csize_max:.0%}
|
|||
Does not access the repository.
|
||||
"""
|
||||
backup_io.op = 'attrs'
|
||||
path_bytes = os.fsencode(path)
|
||||
uid = gid = None
|
||||
if not self.numeric_owner:
|
||||
uid = user2uid(item.user)
|
||||
|
@ -724,33 +722,9 @@ Utilization of max. archive size: {csize_max:.0%}
|
|||
acl_set(path, item, self.numeric_owner)
|
||||
# chown removes Linux capabilities, so set the extended attributes at the end, after chown, since they include
|
||||
# the Linux capabilities in the "security.capability" attribute.
|
||||
xattrs = item.get('xattrs', {})
|
||||
for k, v in xattrs.items():
|
||||
try:
|
||||
# the key k is a bytes object due to msgpack unpacking it as such.
|
||||
# if we have a None value, it means "empty", so give b'' to setxattr in that case:
|
||||
xattr.setxattr(fd or path_bytes, k, v or b'', follow_symlinks=False)
|
||||
except OSError as e:
|
||||
k_str = k.decode()
|
||||
if e.errno == errno.E2BIG:
|
||||
logger.warning('%s: Value or key of extended attribute %s is too big for this filesystem' %
|
||||
(path, k_str))
|
||||
set_ec(EXIT_WARNING)
|
||||
elif e.errno == errno.ENOTSUP:
|
||||
logger.warning('%s: Extended attributes are not supported on this filesystem' % path)
|
||||
set_ec(EXIT_WARNING)
|
||||
elif e.errno == errno.EACCES:
|
||||
# permission denied to set this specific xattr (this may happen related to security.* keys)
|
||||
logger.warning('%s: Permission denied when setting extended attribute %s' % (path, k_str))
|
||||
set_ec(EXIT_WARNING)
|
||||
elif e.errno == errno.ENOSPC:
|
||||
# ext4 reports ENOSPC when trying to set an xattr with >4kiB while ext4 can only support 4kiB xattrs
|
||||
# (in this case, this is NOT a "disk full" error, just a ext4 limitation).
|
||||
logger.warning('%s: No space left on device while setting extended attribute %s (len = %d)' % (
|
||||
path, k_str, len(v)))
|
||||
set_ec(EXIT_WARNING)
|
||||
else:
|
||||
raise
|
||||
warning = xattr.set_all(fd or path, item.get('xattrs', {}), follow_symlinks=False)
|
||||
if warning:
|
||||
set_ec(EXIT_WARNING)
|
||||
# bsdflags include the immutable flag and need to be set last:
|
||||
if not self.nobsdflags and 'bsdflags' in item:
|
||||
try:
|
||||
|
|
|
@ -1264,16 +1264,15 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|||
input_abspath = os.path.abspath('input/file')
|
||||
with patch.object(xattr, 'setxattr', patched_setxattr_E2BIG):
|
||||
out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING)
|
||||
assert out == (input_abspath + ': Value or key of extended attribute attribute is too big for this '
|
||||
'filesystem\n')
|
||||
assert '>: Value or key of extended attribute attribute is too big for this filesystem\n' in out
|
||||
os.remove(input_abspath)
|
||||
with patch.object(xattr, 'setxattr', patched_setxattr_ENOTSUP):
|
||||
out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING)
|
||||
assert out == (input_abspath + ': Extended attributes are not supported on this filesystem\n')
|
||||
assert '>: Extended attributes are not supported on this filesystem\n' in out
|
||||
os.remove(input_abspath)
|
||||
with patch.object(xattr, 'setxattr', patched_setxattr_EACCES):
|
||||
out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING)
|
||||
assert out == (input_abspath + ': Permission denied when setting extended attribute attribute\n')
|
||||
assert '>: Permission denied when setting extended attribute attribute\n' in out
|
||||
assert os.path.isfile(input_abspath)
|
||||
|
||||
def test_path_normalization(self):
|
||||
|
|
|
@ -4,6 +4,10 @@ import errno
|
|||
import os
|
||||
import tempfile
|
||||
|
||||
from .logger import create_logger
|
||||
|
||||
logger = create_logger()
|
||||
|
||||
from .platform import listxattr, getxattr, setxattr, ENOATTR
|
||||
|
||||
XATTR_FAKEROOT = True # fakeroot with xattr support required (>= 1.20.2?)
|
||||
|
@ -20,7 +24,7 @@ def is_enabled(path=None):
|
|||
return getxattr(fd.fileno(), b'user.name') == b'value'
|
||||
|
||||
|
||||
def get_all(path, follow_symlinks=True):
|
||||
def get_all(path, follow_symlinks=False):
|
||||
"""
|
||||
Return all extended attributes on *path* as a mapping.
|
||||
|
||||
|
@ -51,3 +55,48 @@ def get_all(path, follow_symlinks=True):
|
|||
except OSError as e:
|
||||
if e.errno in (errno.ENOTSUP, errno.EPERM):
|
||||
return {}
|
||||
|
||||
|
||||
def set_all(path, xattrs, follow_symlinks=False):
|
||||
"""
|
||||
Set all extended attributes on *path* from a mapping.
|
||||
|
||||
*path* can either be a path (str or bytes) or an open file descriptor (int).
|
||||
*follow_symlinks* indicates whether symlinks should be followed
|
||||
and only applies when *path* is not an open file descriptor.
|
||||
*xattrs* is mapping maps xattr names (bytes) to values (bytes or None).
|
||||
None indicates, as a xattr value, an empty value, i.e. a value of length zero.
|
||||
|
||||
Return warning status (True means a non-fatal exception has happened and was dealt with).
|
||||
"""
|
||||
if isinstance(path, str):
|
||||
path = os.fsencode(path)
|
||||
warning = False
|
||||
for k, v in xattrs.items():
|
||||
try:
|
||||
# the key k is a bytes object due to msgpack unpacking it as such.
|
||||
# if we have a None value, it means "empty", so give b'' to setxattr in that case:
|
||||
setxattr(path, k, v or b'', follow_symlinks=follow_symlinks)
|
||||
except OSError as e:
|
||||
warning = True
|
||||
k_str = k.decode()
|
||||
if isinstance(path, int):
|
||||
path_str = '<FD %d>' % path
|
||||
else:
|
||||
path_str = os.fsdecode(path)
|
||||
if e.errno == errno.E2BIG:
|
||||
logger.warning('%s: Value or key of extended attribute %s is too big for this filesystem' % (
|
||||
path_str, k_str))
|
||||
elif e.errno == errno.ENOTSUP:
|
||||
logger.warning('%s: Extended attributes are not supported on this filesystem' % path_str)
|
||||
elif e.errno == errno.EACCES:
|
||||
# permission denied to set this specific xattr (this may happen related to security.* keys)
|
||||
logger.warning('%s: Permission denied when setting extended attribute %s' % (path_str, k_str))
|
||||
elif e.errno == errno.ENOSPC:
|
||||
# ext4 reports ENOSPC when trying to set an xattr with >4kiB while ext4 can only support 4kiB xattrs
|
||||
# (in this case, this is NOT a "disk full" error, just a ext4 limitation).
|
||||
logger.warning('%s: No space left on device while setting extended attribute %s (len = %d)' % (
|
||||
path_str, k_str, len(v)))
|
||||
else:
|
||||
raise
|
||||
return warning
|
||||
|
|
Loading…
Reference in New Issue