|
@@ -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
|