aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2012-02-22 19:07:11 -0800
committerZac Medico <zmedico@gentoo.org>2012-02-22 19:07:11 -0800
commit0839bb5891f5dfee6e7930de9a2e044859734c04 (patch)
tree400e019560c64c93321e9bfd03cbceb0494dbc2c /pym/portage/dbapi
parentecompressdir: handle abs symlink, bug #405327 (diff)
downloadportage-0839bb5891f5dfee6e7930de9a2e044859734c04.tar.gz
portage-0839bb5891f5dfee6e7930de9a2e044859734c04.tar.bz2
portage-0839bb5891f5dfee6e7930de9a2e044859734c04.zip
dblink: split out _unmerge_dirs method
This code will need to be called twice when safely unmerging symlinks to directories (bug #384397).
Diffstat (limited to 'pym/portage/dbapi')
-rw-r--r--pym/portage/dbapi/vartree.py194
1 files changed, 106 insertions, 88 deletions
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index 96c2530bb..4b1ede121 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -1,4 +1,4 @@
-# Copyright 1998-2011 Gentoo Foundation
+# Copyright 1998-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
__all__ = [
@@ -1388,6 +1388,20 @@ class dblink(object):
r')$'
)
+ # These files are generated by emerge, so we need to remove
+ # them when they are the only thing left in a directory.
+ _infodir_cleanup = frozenset(["dir", "dir.old"])
+
+ _ignored_unlink_errnos = (
+ errno.EBUSY, errno.ENOENT,
+ errno.ENOTDIR, errno.EISDIR)
+
+ _ignored_rmdir_errnos = (
+ errno.EEXIST, errno.ENOTEMPTY,
+ errno.EBUSY, errno.ENOENT,
+ errno.ENOTDIR, errno.EISDIR,
+ errno.EPERM)
+
def __init__(self, cat, pkg, myroot=None, settings=None, treetype=None,
vartree=None, blockers=None, scheduler=None, pipe=None):
"""
@@ -1973,6 +1987,10 @@ class dblink(object):
log_path=log_path, background=background,
level=level, noiselevel=noiselevel)
+ def _show_unmerge(self, zing, desc, file_type, file_name):
+ self._display_merge("%s %s %s %s\n" % \
+ (zing, desc.ljust(8), file_type, file_name))
+
def _unmerge_pkgfiles(self, pkgfiles, others_in_slot):
"""
@@ -1989,6 +2007,9 @@ class dblink(object):
os = _os_merge
perf_md5 = perform_md5
showMessage = self._display_merge
+ show_unmerge = self._show_unmerge
+ ignored_unlink_errnos = self._ignored_unlink_errnos
+ ignored_rmdir_errnos = self._ignored_rmdir_errnos
if not pkgfiles:
showMessage(_("No package files given... Grabbing a set.\n"))
@@ -2024,14 +2045,6 @@ class dblink(object):
#process symlinks second-to-last, directories last.
mydirs = set()
- ignored_unlink_errnos = (
- errno.EBUSY, errno.ENOENT,
- errno.ENOTDIR, errno.EISDIR)
- ignored_rmdir_errnos = (
- errno.EEXIST, errno.ENOTEMPTY,
- errno.EBUSY, errno.ENOENT,
- errno.ENOTDIR, errno.EISDIR,
- errno.EPERM)
modprotect = os.path.join(self._eroot, "lib/modules/")
def unlink(file_name, lstatobj):
@@ -2067,10 +2080,6 @@ class dblink(object):
# Restore the parent flags we saved before unlinking
bsd_chflags.chflags(parent_name, pflags)
- def show_unmerge(zing, desc, file_type, file_name):
- showMessage("%s %s %s %s\n" % \
- (zing, desc.ljust(8), file_type, file_name))
-
unmerge_desc = {}
unmerge_desc["cfgpro"] = _("cfgpro")
unmerge_desc["replaced"] = _("replaced")
@@ -2088,9 +2097,6 @@ class dblink(object):
real_root_len = len(real_root) - 1
eroot = self.settings["EROOT"]
- # These files are generated by emerge, so we need to remove
- # them when they are the only thing left in a directory.
- infodir_cleanup = frozenset(["dir", "dir.old"])
infodirs = frozenset(infodir for infodir in chain(
self.settings.get("INFOPATH", "").split(":"),
self.settings.get("INFODIR", "").split(":")) if infodir)
@@ -2325,78 +2331,8 @@ class dblink(object):
elif pkgfiles[objkey][0] == "dev":
show_unmerge("---", "", file_type, obj)
- mydirs = sorted(mydirs)
- mydirs.reverse()
-
- for obj, inode_key in mydirs:
- # Treat any directory named "info" as a candidate here,
- # since it might have been in INFOPATH previously even
- # though it may not be there now.
- if inode_key in infodirs_inodes or \
- os.path.basename(obj) == "info":
- try:
- remaining = os.listdir(obj)
- except OSError:
- pass
- else:
- cleanup_info_dir = ()
- if remaining and \
- len(remaining) <= len(infodir_cleanup):
- if not set(remaining).difference(infodir_cleanup):
- cleanup_info_dir = remaining
-
- for child in cleanup_info_dir:
- child = os.path.join(obj, child)
- try:
- lstatobj = os.lstat(child)
- if stat.S_ISREG(lstatobj.st_mode):
- unlink(child, lstatobj)
- show_unmerge("<<<", "", "obj", child)
- except EnvironmentError as e:
- if e.errno not in ignored_unlink_errnos:
- raise
- del e
- show_unmerge("!!!", "", "obj", child)
- try:
- if bsd_chflags:
- lstatobj = os.lstat(obj)
- if lstatobj.st_flags != 0:
- bsd_chflags.lchflags(obj, 0)
- parent_name = os.path.dirname(obj)
- # Use normal stat/chflags for the parent since we want to
- # follow any symlinks to the real parent directory.
- pflags = os.stat(parent_name).st_flags
- if pflags != 0:
- bsd_chflags.chflags(parent_name, 0)
- try:
- os.rmdir(obj)
- finally:
- if bsd_chflags and pflags != 0:
- # Restore the parent flags we saved before unlinking
- bsd_chflags.chflags(parent_name, pflags)
- show_unmerge("<<<", "", "dir", obj)
- except EnvironmentError as e:
- if e.errno not in ignored_rmdir_errnos:
- raise
- if e.errno != errno.ENOENT:
- show_unmerge("---", unmerge_desc["!empty"], "dir", obj)
- del e
- else:
- # When a directory is successfully removed, there's
- # no need to protect symlinks that point to it.
- unmerge_syms = protected_symlinks.pop(inode_key, None)
- if unmerge_syms is not None:
- for relative_path in unmerge_syms:
- obj = os.path.join(real_root,
- relative_path.lstrip(os.sep))
- try:
- unlink(obj, os.lstat(obj))
- show_unmerge("<<<", "", "sym", obj)
- except (OSError, IOError) as e:
- if e.errno not in ignored_unlink_errnos:
- raise
- del e
- show_unmerge("!!!", "", "sym", obj)
+ self._unmerge_dirs(mydirs, infodirs_inodes,
+ protected_symlinks, unmerge_desc, unlink, os)
if protected_symlinks:
msg = "One or more symlinks to directories have been " + \
@@ -2422,6 +2358,88 @@ class dblink(object):
#remove self from vartree database so that our own virtual gets zapped if we're the last node
self.vartree.zap(self.mycpv)
+ def _unmerge_dirs(self, dirs, infodirs_inodes,
+ protected_symlinks, unmerge_desc, unlink, os):
+
+ show_unmerge = self._show_unmerge
+ infodir_cleanup = self._infodir_cleanup
+ ignored_unlink_errnos = self._ignored_unlink_errnos
+ ignored_rmdir_errnos = self._ignored_rmdir_errnos
+ real_root = self.settings['ROOT']
+
+ dirs = sorted(dirs)
+ dirs.reverse()
+
+ for obj, inode_key in dirs:
+ # Treat any directory named "info" as a candidate here,
+ # since it might have been in INFOPATH previously even
+ # though it may not be there now.
+ if inode_key in infodirs_inodes or \
+ os.path.basename(obj) == "info":
+ try:
+ remaining = os.listdir(obj)
+ except OSError:
+ pass
+ else:
+ cleanup_info_dir = ()
+ if remaining and \
+ len(remaining) <= len(infodir_cleanup):
+ if not set(remaining).difference(infodir_cleanup):
+ cleanup_info_dir = remaining
+
+ for child in cleanup_info_dir:
+ child = os.path.join(obj, child)
+ try:
+ lstatobj = os.lstat(child)
+ if stat.S_ISREG(lstatobj.st_mode):
+ unlink(child, lstatobj)
+ show_unmerge("<<<", "", "obj", child)
+ except EnvironmentError as e:
+ if e.errno not in ignored_unlink_errnos:
+ raise
+ del e
+ show_unmerge("!!!", "", "obj", child)
+ try:
+ if bsd_chflags:
+ lstatobj = os.lstat(obj)
+ if lstatobj.st_flags != 0:
+ bsd_chflags.lchflags(obj, 0)
+ parent_name = os.path.dirname(obj)
+ # Use normal stat/chflags for the parent since we want to
+ # follow any symlinks to the real parent directory.
+ pflags = os.stat(parent_name).st_flags
+ if pflags != 0:
+ bsd_chflags.chflags(parent_name, 0)
+ try:
+ os.rmdir(obj)
+ finally:
+ if bsd_chflags and pflags != 0:
+ # Restore the parent flags we saved before unlinking
+ bsd_chflags.chflags(parent_name, pflags)
+ show_unmerge("<<<", "", "dir", obj)
+ except EnvironmentError as e:
+ if e.errno not in ignored_rmdir_errnos:
+ raise
+ if e.errno != errno.ENOENT:
+ show_unmerge("---", unmerge_desc["!empty"], "dir", obj)
+ del e
+ else:
+ # When a directory is successfully removed, there's
+ # no need to protect symlinks that point to it.
+ unmerge_syms = protected_symlinks.pop(inode_key, None)
+ if unmerge_syms is not None:
+ for relative_path in unmerge_syms:
+ obj = os.path.join(real_root,
+ relative_path.lstrip(os.sep))
+ try:
+ unlink(obj, os.lstat(obj))
+ show_unmerge("<<<", "", "sym", obj)
+ except (OSError, IOError) as e:
+ if e.errno not in ignored_unlink_errnos:
+ raise
+ del e
+ show_unmerge("!!!", "", "sym", obj)
+
def isowner(self, filename, destroot=None):
"""
Check if a file belongs to this package. This may