Source code for craft_parts.xattrs
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright 2019-2023 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Helpers to read and write filesystem extended attributes."""
import logging
import os
import sys
from typing import Optional
from craft_parts import errors
logger = logging.getLogger(__name__)
[docs]def read_xattr(path: str, key: str) -> Optional[str]:
"""Get extended attribute metadata from a file.
:param path: The file to get metadata from.
:param key: The attribute key.
:return: The attribute value.
"""
if sys.platform != "linux":
raise RuntimeError("xattr support only available for Linux")
# Extended attributes do not apply to symlinks.
if os.path.islink(path):
return None
key = f"user.craft_parts.{key}"
try:
value = os.getxattr(path, key)
except OSError as error:
# No label present with:
# OSError: [Errno 61] No data available: b'<path>'
if error.errno == 61:
return None
# Chain unknown variants of OSError.
raise errors.XAttributeError(key=key, path=path) from error
return value.decode().strip()
[docs]def write_xattr(path: str, key: str, value: str) -> None:
"""Add extended attribute metadata to a file.
:param path: The file to add metadata to.
:param key: The attribute key.
:param value: The attribute value.
"""
if sys.platform != "linux":
raise RuntimeError("xattr support only available for Linux")
# Extended attributes do not apply to symlinks.
if os.path.islink(path):
return
key = f"user.craft_parts.{key}"
try:
os.setxattr(path, key, value.encode())
except OSError as error:
# Label is too long for filesystem:
# OSError: [Errno 7] Argument list too long: b'<path>'
if error.errno == 7:
raise errors.XAttributeTooLong(path=path, key=key, value=value)
# Chain unknown variants of OSError.
raise errors.XAttributeError(key=key, path=path, is_write=True) from error