directory.py revision 462
409N/A#!/usr/bin/python2.4
49N/A#
49N/A# CDDL HEADER START
49N/A#
49N/A# The contents of this file are subject to the terms of the
49N/A# Common Development and Distribution License (the "License").
49N/A# You may not use this file except in compliance with the License.
49N/A#
49N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
49N/A# or http://www.opensolaris.org/os/licensing.
49N/A# See the License for the specific language governing permissions
49N/A# and limitations under the License.
49N/A#
49N/A# When distributing Covered Code, include this CDDL HEADER in each
49N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
49N/A# If applicable, add the following below this CDDL HEADER, with the
49N/A# fields enclosed by brackets "[]" replaced with your own identifying
49N/A# information: Portions Copyright [yyyy] [name of copyright owner]
49N/A#
49N/A# CDDL HEADER END
49N/A#
49N/A
49N/A#
289N/A# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
49N/A# Use is subject to license terms.
49N/A#
49N/A
49N/A"""module describing a directory packaging object
49N/A
49N/AThis module contains the DirectoryAction class, which represents a
49N/Adirectory-type packaging object."""
49N/A
51N/Aimport os
51N/Aimport errno
222N/Afrom stat import *
49N/Aimport generic
289N/Aimport pkg.portable as portable
49N/A
49N/Aclass DirectoryAction(generic.Action):
49N/A """Class representing a directory-type packaging object."""
49N/A
51N/A name = "dir"
51N/A attributes = ("mode", "owner", "group", "path")
72N/A key_attr = "path"
51N/A
49N/A def __init__(self, data=None, **attrs):
49N/A generic.Action.__init__(self, data, **attrs)
49N/A
307N/A def compare(self, other):
307N/A return cmp(self.attrs["path"], other.attrs["path"])
307N/A
307N/A def directory_references(self):
307N/A return [os.path.normpath(self.attrs["path"])]
281N/A
136N/A def install(self, pkgplan, orig):
49N/A """Client-side method that installs a directory."""
51N/A path = self.attrs["path"]
51N/A mode = int(self.attrs["mode"], 8)
289N/A owner = pkgplan.image.get_user_by_name(self.attrs["owner"])
289N/A group = pkgplan.image.get_group_by_name(self.attrs["group"])
51N/A
72N/A if orig:
72N/A omode = int(orig.attrs["mode"], 8)
289N/A oowner = pkgplan.image.get_user_by_name(
289N/A orig.attrs["owner"])
289N/A ogroup = pkgplan.image.get_group_by_name(
289N/A orig.attrs["group"])
72N/A
53N/A path = os.path.normpath(os.path.sep.join(
136N/A (pkgplan.image.get_root(), path)))
51N/A
95N/A # XXX Hack! (See below comment.)
289N/A if not portable.is_admin():
170N/A mode |= 0200
95N/A
72N/A if not orig:
72N/A try:
136N/A self.makedirs(path, mode = mode)
72N/A except OSError, e:
72N/A if e.errno != errno.EEXIST:
72N/A raise
95N/A
95N/A # The downside of chmodding the directory is that as a non-root
95N/A # user, if we set perms u-w, we won't be able to put anything in
95N/A # it, which is often not what we want at install time. We save
95N/A # the chmods for the postinstall phase, but it's always possible
95N/A # that a later package install will want to place something in
95N/A # this directory and then be unable to. So perhaps we need to
95N/A # (in all action types) chmod the parent directory to u+w on
95N/A # failure, and chmod it back aftwards. The trick is to
95N/A # recognize failure due to missing file_dac_write in contrast to
95N/A # other failures. Or can we require that everyone simply have
95N/A # file_dac_write who wants to use the tools. Probably not.
72N/A elif mode != omode:
72N/A os.chmod(path, mode)
49N/A
72N/A if not orig or oowner != owner or ogroup != group:
72N/A try:
289N/A portable.chown(path, owner, group)
72N/A except OSError, e:
271N/A if e.errno != errno.EPERM and \
271N/A e.errno != errno.ENOSYS:
72N/A raise
66N/A
235N/A def verify(self, img, **args):
235N/A """ make sure directory is correctly installed"""
222N/A
222N/A mode = int(self.attrs["mode"], 8)
289N/A owner = img.get_user_by_name(self.attrs["owner"])
289N/A group = img.get_group_by_name(self.attrs["group"])
222N/A
235N/A path = os.path.normpath(os.path.sep.join((img.get_root(),
235N/A self.attrs["path"])))
235N/A try:
235N/A stat = os.lstat(path)
235N/A except OSError, e:
235N/A if e.errno == errno.ENOENT:
235N/A return ["Directory does not exist"]
235N/A if e.errno == errno.EACCES:
235N/A return ["Skipping: Permission denied"]
235N/A return ["Unexpected exception: %s" % e]
222N/A
235N/A errors = []
235N/A
235N/A if not S_ISDIR(stat[ST_MODE]):
235N/A errors.append("Not a directory")
222N/A
235N/A if stat[ST_UID] != owner:
235N/A errors.append("Owner: '%s' should be '%s'" % \
339N/A (img.get_name_by_uid(stat[ST_UID], True),
339N/A img.get_name_by_uid(owner, True)))
235N/A if stat[ST_GID] != group:
235N/A errors.append("Group: '%s' should be '%s'" % \
339N/A (img.get_name_by_gid(stat[ST_GID], True),
339N/A img.get_name_by_gid(group, True)))
222N/A
235N/A if S_IMODE(stat[ST_MODE]) != mode:
235N/A errors.append("Mode: 0%.3o should be 0%.3o" % \
235N/A (S_IMODE(stat[ST_MODE]), mode))
222N/A
307N/A return errors
289N/A
136N/A def remove(self, pkgplan):
307N/A localpath = os.path.normpath(self.attrs["path"])
462N/A path = os.path.normpath(os.path.sep.join(
462N/A (pkgplan.image.get_root(), localpath)))
462N/A try:
462N/A os.rmdir(path)
462N/A except OSError, e:
462N/A if e.errno == errno.ENOENT:
462N/A pass
462N/A elif e.errno == errno.EEXIST or \
462N/A e.errno == errno.ENOTEMPTY:
462N/A # cannot remove directory since it's
462N/A # not empty...
462N/A pkgplan.image.salvagedir(localpath)
462N/A elif e.errno != errno.EACCES: # this happens on Windows
462N/A raise
140N/A
144N/A def generate_indices(self):
140N/A return {
140N/A "basename": os.path.basename(self.attrs["path"]),
144N/A "path": os.path.sep + self.attrs["path"]
140N/A }