hardlink.py revision 1685
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#!/usr/bin/python
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# CDDL HEADER START
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# The contents of this file are subject to the terms of the
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# Common Development and Distribution License (the "License").
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# You may not use this file except in compliance with the License.
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# or http://www.opensolaris.org/os/licensing.
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# See the License for the specific language governing permissions
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# and limitations under the License.
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# When distributing Covered Code, include this CDDL HEADER in each
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# If applicable, add the following below this CDDL HEADER, with the
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# fields enclosed by brackets "[]" replaced with your own identifying
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# information: Portions Copyright [yyyy] [name of copyright owner]
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# CDDL HEADER END
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen# Use is subject to license terms.
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen#
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen"""module describing a (hard) link packaging object
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo SirainenThis module contains the HardLinkAction class, which represents a hardlink-type
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenpackaging object."""
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenimport errno
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenimport link
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenimport os
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenimport stat
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenfrom pkg import misc
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenfrom pkg.client.api_errors import ActionExecutionError
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenclass HardLinkAction(link.LinkAction):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen """Class representing a hardlink-type packaging object."""
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen name = "hardlink"
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen def __init__(self, data=None, **attrs):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen link.LinkAction.__init__(self, data, **attrs)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen def get_target_path(self):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen """ return a path for target that is relative to image"""
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen target = self.attrs["target"]
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen # paths are either relative to path or absolute;
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen # both need to be passed through os.path.normpath to ensure
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen # that all ".." are removed to constrain target to image
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen if target[0] != "/":
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen path = self.attrs["path"]
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen target = os.path.normpath(
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen os.path.join(os.path.split(path)[0], target))
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen else:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen target = os.path.normpath(target)[1:]
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen return target
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen def install(self, pkgplan, orig):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen """Client-side method that installs a hard link."""
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen path = self.attrs["path"]
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen target = self.get_target_path()
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen path = os.path.normpath(os.path.sep.join(
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen (pkgplan.image.get_root(), path)))
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen if not os.path.exists(os.path.dirname(path)):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen self.makedirs(os.path.dirname(path),
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen mode=misc.PKG_DIR_MODE)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen elif os.path.exists(path):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen os.unlink(path)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen fulltarget = os.path.normpath(os.path.sep.join(
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen (pkgplan.image.get_root(), target)))
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen try:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen os.link(fulltarget, path)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen except EnvironmentError, e:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen if e.errno == errno.ENOENT:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen raise ActionExecutionError(self, e,
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen "missing hard link target '%s'" % target)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen else:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen raise ActionExecutionError(self, e)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen def verify(self, img, **args):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen """Returns a tuple of lists of the form (errors, warnings,
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen info). The error list will be empty if the action has been
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen correctly installed in the given image."""
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen #
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen # We only allow hard links to regular files, so the hard
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen # link should lstat() as a regular file.
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen #
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen lstat, errors, warnings, info, abort = \
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen self.verify_fsobj_common(img, stat.S_IFREG)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen if abort:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen assert errors
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen return errors, warnings, info
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen target = self.get_target_path()
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen path = os.path.normpath(os.path.sep.join(
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen (img.get_root(), self.attrs["path"])))
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen target = os.path.normpath(os.path.sep.join(
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen (img.get_root(), target)))
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen if not os.path.exists(target):
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen errors.append(_("Target '%s' does not exist") %
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen self.attrs["target"])
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen # No point in continuing if no target
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen if errors:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen return errors, warnings, info
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen try:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen if os.stat(path).st_ino != os.stat(target).st_ino:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen errors.append(_("Broken: Path and Target (%s) "
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen "inodes not the same") %
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen self.get_target_path())
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen except OSError, e:
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen errors.append(_("Unexpected Error: %s") % e)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen return errors, warnings, info
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen