From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 802931389F5 for ; Sat, 15 Nov 2014 07:22:21 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 4B02DE0AA4; Sat, 15 Nov 2014 07:22:17 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id B7680E0AA1 for ; Sat, 15 Nov 2014 07:22:16 +0000 (UTC) Received: from localhost.localdomain (ip70-181-96-121.oc.oc.cox.net [70.181.96.121]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: zmedico) by smtp.gentoo.org (Postfix) with ESMTPSA id 96621340CAD; Sat, 15 Nov 2014 07:22:15 +0000 (UTC) From: Zac Medico To: gentoo-portage-dev@lists.gentoo.org Cc: Zac Medico Subject: [gentoo-portage-dev] [PATCH] unprivileged mode: use first_existing helper func Date: Fri, 14 Nov 2014 23:21:54 -0800 Message-Id: <1416036114-13046-1-git-send-email-zmedico@gentoo.org> X-Mailer: git-send-email 2.0.4 In-Reply-To: <5466E26D.6090802@gentoo.org> References: <5466E26D.6090802@gentoo.org> Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-portage-dev@lists.gentoo.org Reply-to: gentoo-portage-dev@lists.gentoo.org X-Archives-Salt: 0b64a178-20e3-43d5-9e53-6e8fe917cdd2 X-Archives-Hash: 7098073a73070f6bc2681df0b3cbc55b Split out a first_existing function, in order to improve logic related to the _unprivileged_mode function so that it checks whether it's possible to create the specified target root (instead of requiring that the target root already exists). --- pym/portage/data.py | 20 +++++++++------ pym/portage/package/ebuild/config.py | 23 ++++++----------- pym/portage/util/path.py | 48 ++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 pym/portage/util/path.py diff --git a/pym/portage/data.py b/pym/portage/data.py index 3e03eef..d9b36ee 100644 --- a/pym/portage/data.py +++ b/pym/portage/data.py @@ -8,6 +8,7 @@ import portage portage.proxy.lazyimport.lazyimport(globals(), 'portage.output:colorize', 'portage.util:writemsg', + 'portage.util.path:first_existing', 'subprocess' ) from portage.localization import _ @@ -94,14 +95,16 @@ def _get_global(k): else: # The config class has equivalent code, but we also need to # do it here if _disable_legacy_globals() has been called. - eroot = os.path.join(os.environ.get('ROOT', os.sep), - portage.const.EPREFIX.lstrip(os.sep)) + eroot_or_parent = first_existing(os.path.join( + os.environ.get('ROOT', os.sep), + portage.const.EPREFIX.lstrip(os.sep))) try: - eroot_st = os.stat(eroot) + eroot_st = os.stat(eroot_or_parent) except OSError: pass else: - unprivileged = _unprivileged_mode(eroot, eroot_st) + unprivileged = _unprivileged_mode( + eroot_or_parent, eroot_st) v = 0 if uid == 0: @@ -206,14 +209,15 @@ def _get_global(k): else: # The config class has equivalent code, but we also need to # do it here if _disable_legacy_globals() has been called. - eroot = os.path.join(os.environ.get('ROOT', os.sep), - portage.const.EPREFIX.lstrip(os.sep)) + eroot_or_parent = first_existing(os.path.join( + os.environ.get('ROOT', os.sep), + portage.const.EPREFIX.lstrip(os.sep))) try: - eroot_st = os.stat(eroot) + eroot_st = os.stat(eroot_or_parent) except OSError: pass else: - if _unprivileged_mode(eroot, eroot_st): + if _unprivileged_mode(eroot_or_parent, eroot_st): if k == '_portage_grpname': try: grp_struct = grp.getgrgid(eroot_st.st_gid) diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py index c7308a4..bf39487 100644 --- a/pym/portage/package/ebuild/config.py +++ b/pym/portage/package/ebuild/config.py @@ -48,6 +48,7 @@ from portage.util import ensure_dirs, getconfig, grabdict, \ grabdict_package, grabfile, grabfile_package, LazyItemsDict, \ normalize_path, shlex_split, stack_dictlist, stack_dicts, stack_lists, \ writemsg, writemsg_level, _eapi_cache +from portage.util.path import first_existing from portage.util._path import exists_raise_eaccess, isdir_raise_eaccess from portage.versions import catpkgsplit, catsplit, cpv_getkey, _pkg_str @@ -848,14 +849,16 @@ class config(object): "PORTAGE_INST_UID": "0", } + eroot_or_parent = first_existing(eroot) unprivileged = False try: - eroot_st = os.stat(eroot) + eroot_st = os.stat(eroot_or_parent) except OSError: pass else: - if portage.data._unprivileged_mode(eroot, eroot_st): + if portage.data._unprivileged_mode( + eroot_or_parent, eroot_st): unprivileged = True default_inst_ids["PORTAGE_INST_GID"] = str(eroot_st.st_gid) @@ -897,20 +900,8 @@ class config(object): # In unprivileged mode, automatically make # depcachedir relative to target_root if the # default depcachedir is not writable. - current_dir = self.depcachedir - found_dir = False - while current_dir != os.sep and not found_dir: - try: - os.stat(current_dir) - found_dir = True - except OSError as e: - if e.errno == errno.ENOENT: - current_dir = os.path.dirname( - current_dir) - else: - found_dir = True - - if not os.access(current_dir, os.W_OK): + if not os.access(first_existing(self.depcachedir), + os.W_OK): self.depcachedir = os.path.join(eroot, DEPCACHE_PATH.lstrip(os.sep)) diff --git a/pym/portage/util/path.py b/pym/portage/util/path.py new file mode 100644 index 0000000..f77f30f --- /dev/null +++ b/pym/portage/util/path.py @@ -0,0 +1,48 @@ +# Copyright 2014 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import errno + +from portage import os + +def first_existing(path): + """ + Returns the first existing path element, traversing from the given + path to the root directory. A path is considered to exists if lstat + either succeeds or raises an error other than ENOENT or ESTALE. + + This can be particularly useful to check if there is permission to + create a particular file or directory, without actually creating + anything. + + @param path: a filesystem path + @type path: str + @rtype: str + @return: the element that exists + """ + existing = False + for path in iter_parents(path): + try: + os.lstat(path) + existing = True + except OSError as e: + if e.errno not in (errno.ENOENT, errno.ESTALE): + existing = True + + if existing: + return path + + return os.sep + +def iter_parents(path): + """ + @param path: a filesystem path + @type path: str + @rtype: iterator + @return: an iterator which yields path and all parents of path, + ending with the root directory + """ + yield path + while path != os.sep: + path = os.path.dirname(path) + yield path -- 2.0.4