directory.py revision 1713
1516N/A#!/usr/bin/python
565N/A#
565N/A# CDDL HEADER START
565N/A#
565N/A# The contents of this file are subject to the terms of the
565N/A# Common Development and Distribution License (the "License").
565N/A# You may not use this file except in compliance with the License.
565N/A#
565N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
565N/A# or http://www.opensolaris.org/os/licensing.
565N/A# See the License for the specific language governing permissions
565N/A# and limitations under the License.
565N/A#
565N/A# When distributing Covered Code, include this CDDL HEADER in each
565N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
565N/A# If applicable, add the following below this CDDL HEADER, with the
565N/A# fields enclosed by brackets "[]" replaced with your own identifying
565N/A# information: Portions Copyright [yyyy] [name of copyright owner]
565N/A#
565N/A# CDDL HEADER END
565N/A#
926N/A
926N/A#
2614N/A# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
926N/A# Use is subject to license terms.
565N/A#
2026N/A
1050N/A"""module describing a directory packaging object
2524N/A
926N/AThis module contains the DirectoryAction class, which represents a
926N/Adirectory-type packaging object."""
2339N/A
2339N/Aimport os
2339N/Aimport errno
926N/Aimport stat
926N/Aimport generic
926N/Aimport pkg.portable as portable
838N/Aimport pkg.actions
565N/A
2034N/Aclass DirectoryAction(generic.Action):
2034N/A """Class representing a directory-type packaging object."""
2034N/A
1540N/A name = "dir"
1540N/A attributes = ("mode", "owner", "group", "path")
1540N/A key_attr = "path"
1540N/A globally_unique = True
1540N/A
1968N/A def __init__(self, data=None, **attrs):
1540N/A generic.Action.__init__(self, data, **attrs)
2034N/A if "path" in self.attrs:
2034N/A self.attrs["path"] = self.attrs["path"].lstrip(
2200N/A os.path.sep)
2034N/A if not self.attrs["path"]:
2034N/A raise pkg.actions.InvalidActionError(
2034N/A str(self), _("Empty path attribute"))
565N/A
2339N/A def compare(self, other):
2339N/A return cmp(self.attrs["path"], other.attrs["path"])
2339N/A
2339N/A def directory_references(self):
2339N/A return [os.path.normpath(self.attrs["path"])]
2339N/A
2524N/A def install(self, pkgplan, orig):
2524N/A """Client-side method that installs a directory."""
2524N/A path = self.attrs["path"]
2524N/A mode = int(self.attrs["mode"], 8)
2524N/A owner = pkgplan.image.get_user_by_name(self.attrs["owner"])
2524N/A group = pkgplan.image.get_group_by_name(self.attrs["group"])
2524N/A
2524N/A if orig:
2524N/A omode = int(orig.attrs["mode"], 8)
2524N/A oowner = pkgplan.image.get_user_by_name(
2524N/A orig.attrs["owner"])
2524N/A ogroup = pkgplan.image.get_group_by_name(
2524N/A orig.attrs["group"])
2524N/A
2524N/A path = os.path.normpath(os.path.sep.join(
2524N/A (pkgplan.image.get_root(), path)))
2524N/A
2524N/A # XXX Hack! (See below comment.)
2524N/A if not portable.is_admin():
2524N/A mode |= stat.S_IWUSR
2524N/A
2524N/A if not orig:
2524N/A try:
2524N/A self.makedirs(path, mode = mode)
2524N/A except OSError, e:
2524N/A if e.errno != errno.EEXIST:
2524N/A raise
2524N/A
2524N/A # The downside of chmodding the directory is that as a non-root
2524N/A # user, if we set perms u-w, we won't be able to put anything in
2524N/A # it, which is often not what we want at install time. We save
2524N/A # the chmods for the postinstall phase, but it's always possible
2524N/A # that a later package install will want to place something in
2524N/A # this directory and then be unable to. So perhaps we need to
2524N/A # (in all action types) chmod the parent directory to u+w on
2524N/A # failure, and chmod it back aftwards. The trick is to
2524N/A # recognize failure due to missing file_dac_write in contrast to
2524N/A # other failures. Or can we require that everyone simply have
2524N/A # file_dac_write who wants to use the tools. Probably not.
2524N/A elif mode != omode:
2524N/A os.chmod(path, mode)
2524N/A
2524N/A if not orig or oowner != owner or ogroup != group:
2524N/A try:
2524N/A portable.chown(path, owner, group)
2524N/A except OSError, e:
2524N/A if e.errno != errno.EPERM and \
2524N/A e.errno != errno.ENOSYS:
2524N/A raise
1710N/A
1710N/A def verify(self, img, **args):
1710N/A """Returns a tuple of lists of the form (errors, warnings,
1710N/A info). The error list will be empty if the action has been
1710N/A correctly installed in the given image."""
1710N/A
1710N/A lstat, errors, warnings, info, abort = \
1710N/A self.verify_fsobj_common(img, stat.S_IFDIR)
1710N/A return errors, warnings, info
1710N/A
1710N/A def remove(self, pkgplan):
1710N/A localpath = os.path.normpath(self.attrs["path"])
1710N/A path = os.path.normpath(os.path.sep.join(
1710N/A (pkgplan.image.get_root(), localpath)))
1710N/A try:
1710N/A os.rmdir(path)
1710N/A except OSError, e:
1710N/A if e.errno == errno.ENOENT:
1710N/A pass
1710N/A elif e.errno == errno.EEXIST or \
1710N/A e.errno == errno.ENOTEMPTY:
1710N/A # cannot remove directory since it's
1710N/A # not empty...
1710N/A pkgplan.image.salvagedir(localpath)
1710N/A elif e.errno != errno.EACCES: # this happens on Windows
1710N/A raise
1710N/A
1710N/A def generate_indices(self):
1710N/A """Generates the indices needed by the search dictionary. See
1710N/A generic.py for a more detailed explanation."""
1710N/A
565N/A return [
565N/A ("directory", "basename",
565N/A os.path.basename(self.attrs["path"].rstrip(os.path.sep)),
565N/A None),
565N/A ("directory", "path", os.path.sep + self.attrs["path"],
565N/A None)
565N/A ]
565N/A