# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-## Copyright 2021 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/>."""Low level interface to OS overlayfs."""importloggingimportosfrompathlibimportPathfromsubprocessimportCalledProcessErrorfromcraft_parts.utilsimportos_utilsfrom.importerrorslogger=logging.getLogger(__name__)
[docs]defmount(self,mountpoint:Path)->None:"""Mount an overlayfs. :param mountpoint: The filesystem mount point. :raises OverlayMountError: on mount error. """logger.debug("mount overlayfs on %s",mountpoint)lower_dir=":".join([str(p)forpinself._lower_dirs])try:os_utils.mount_overlayfs(str(mountpoint),f"-olowerdir={lower_dir!s},upperdir={self._upper_dir!s},"f"workdir={self._work_dir!s}",)exceptCalledProcessErroraserr:raiseerrors.OverlayMountError(str(mountpoint),message=str(err))fromerrself._mountpoint=mountpoint
[docs]defunmount(self)->None:"""Umount an overlayfs. :raises OverlayUnmountError: on unmount error. """ifnotself._mountpoint:returnlogger.debug("unmount overlayfs from %s",self._mountpoint)try:os_utils.umount(str(self._mountpoint))exceptCalledProcessErroraserr:raiseerrors.OverlayUnmountError(str(self._mountpoint),message=str(err))fromerrself._mountpoint=None
[docs]defis_whiteout_file(path:Path)->bool:"""Verify if the given path corresponds to a whiteout file. Overlayfs whiteout files are represented as character devices with major and minor numbers set to 0. :param path: The path of the file to verify. :returns: Whether the given path is an overlayfs whiteout. """ifnotpath.is_char_device()orpath.is_symlink():returnFalserdev=os.stat(path).st_rdevreturnos.major(rdev)==0andos.minor(rdev)==0
[docs]defis_opaque_dir(path:Path)->bool:"""Verify if the given path corresponds to an opaque directory. Overlayfs opaque directories are represented by directories with the extended attribute `trusted.overlay.opaque` set to `y`. :param path: The path of the file to verify. :returns: Whether the given path is an overlayfs opaque directory. """ifnotpath.is_dir()orpath.is_symlink():returnFalsetry:value=os.getxattr(path,"trusted.overlay.opaque")exceptOSError:returnFalsereturnvalue==b"y"