Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH v2] ro_checker: only check nearest parent (bug 547390)
Date: Tue, 28 Apr 2015 14:48:26
Message-Id: 1430107168-18968-1-git-send-email-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] ro_checker: only check nearest parent (bug 547390) by Zac Medico
1 The ro_checker code added in commit
2 47ef9a0969474f963dc8e52bfbbb8bc075e8d73c incorrectly asserts that all
3 parent directories be writable. Fix it to only assert that the nearest
4 parent directory be writable.
5
6 Fixes 47ef9a096947: ("Test for read-only filesystems, fixes bug 378869")
7 X-Gentoo-Bug: 547390
8 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=547390
9 ---
10 [PATCH v2] fixes writeable_check to compare device numbers
11
12 pym/portage/dbapi/vartree.py | 44 +++++++++++++++++++++----------------
13 pym/portage/util/writeable_check.py | 22 +++++++++++++++++--
14 2 files changed, 45 insertions(+), 21 deletions(-)
15
16 diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
17 index 1c0deab..c59d778 100644
18 --- a/pym/portage/dbapi/vartree.py
19 +++ b/pym/portage/dbapi/vartree.py
20 @@ -33,7 +33,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
21 'portage.util.env_update:env_update',
22 'portage.util.listdir:dircache,listdir',
23 'portage.util.movefile:movefile',
24 - 'portage.util.path:first_existing',
25 + 'portage.util.path:first_existing,iter_parents',
26 'portage.util.writeable_check:get_ro_checker',
27 'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry',
28 'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap',
29 @@ -3325,6 +3325,8 @@ class dblink(object):
30 showMessage = self._display_merge
31 stopmerge = False
32 collisions = []
33 + dirs = set()
34 + dirs_ro = set()
35 symlink_collisions = []
36 destroot = self.settings['ROOT']
37 showMessage(_(" %s checking %d files for package collisions\n") % \
38 @@ -3337,6 +3339,18 @@ class dblink(object):
39
40 dest_path = normalize_path(
41 os.path.join(destroot, f.lstrip(os.path.sep)))
42 +
43 + parent = os.path.dirname(dest_path)
44 + if parent not in dirs:
45 + for x in iter_parents(parent):
46 + if x in dirs:
47 + break
48 + dirs.add(x)
49 + if os.path.isdir(x):
50 + if not os.access(x, os.W_OK):
51 + dirs_ro.add(x)
52 + break
53 +
54 try:
55 dest_lstat = os.lstat(dest_path)
56 except EnvironmentError as e:
57 @@ -3410,7 +3424,7 @@ class dblink(object):
58 break
59 if stopmerge:
60 collisions.append(f)
61 - return collisions, symlink_collisions, plib_collisions
62 + return collisions, dirs_ro, symlink_collisions, plib_collisions
63
64 def _lstat_inode_map(self, path_iter):
65 """
66 @@ -3759,7 +3773,6 @@ class dblink(object):
67 eagain_error = False
68
69 filelist = []
70 - dirlist = []
71 linklist = []
72 paths_with_newlines = []
73 def onerror(e):
74 @@ -3792,13 +3805,6 @@ class dblink(object):
75 unicode_errors.append(new_parent[ed_len:])
76 break
77
78 - relative_path = parent[srcroot_len:]
79 - if len(relative_path) >= eprefix_len:
80 - # Files are never installed outside of the prefix,
81 - # therefore we skip the readonly filesystem check for
82 - # parent directories of the prefix (see bug 544624).
83 - dirlist.append(os.path.join(destroot, relative_path))
84 -
85 for fname in files:
86 try:
87 fname = _unicode_decode(fname,
88 @@ -3911,9 +3917,17 @@ class dblink(object):
89 for other in others_in_slot])
90 prepare_build_dirs(settings=self.settings, cleanup=cleanup)
91
92 + # check for package collisions
93 + blockers = self._blockers
94 + if blockers is None:
95 + blockers = []
96 + collisions, dirs_ro, symlink_collisions, plib_collisions = \
97 + self._collision_protect(srcroot, destroot,
98 + others_in_slot + blockers, filelist, linklist)
99 +
100 # Check for read-only filesystems.
101 ro_checker = get_ro_checker()
102 - rofilesystems = ro_checker(dirlist)
103 + rofilesystems = ro_checker(dirs_ro)
104
105 if rofilesystems:
106 msg = _("One or more files installed to this package are "
107 @@ -3935,14 +3949,6 @@ class dblink(object):
108 eerror(msg)
109 return 1
110
111 - # check for package collisions
112 - blockers = self._blockers
113 - if blockers is None:
114 - blockers = []
115 - collisions, symlink_collisions, plib_collisions = \
116 - self._collision_protect(srcroot, destroot,
117 - others_in_slot + blockers, filelist, linklist)
118 -
119 if symlink_collisions:
120 # Symlink collisions need to be distinguished from other types
121 # of collisions, in order to avoid confusion (see bug #409359).
122 diff --git a/pym/portage/util/writeable_check.py b/pym/portage/util/writeable_check.py
123 index 445b2c2..0f7c08b 100644
124 --- a/pym/portage/util/writeable_check.py
125 +++ b/pym/portage/util/writeable_check.py
126 @@ -1,5 +1,5 @@
127 #-*- coding:utf-8 -*-
128 -# Copyright 2014 Gentoo Foundation
129 +# Copyright 2014-2015 Gentoo Foundation
130 # Distributed under the terms of the GNU General Public License v2
131 """
132 Methods to check whether Portage is going to write to read-only filesystems.
133 @@ -13,6 +13,7 @@ from __future__ import unicode_literals
134
135 import io
136 import logging
137 +import os
138
139 from portage import _encodings
140 from portage.util import writemsg_level
141 @@ -68,7 +69,24 @@ def linux_ro_checker(dir_list):
142 level=logging.WARNING, noiselevel=-1)
143 return []
144
145 - return set.intersection(ro_filesystems, set(dir_list))
146 + ro_devs = set()
147 + for x in ro_filesystems:
148 + try:
149 + ro_devs.add(os.stat(x).st_dev)
150 + except OSError:
151 + pass
152 +
153 + ro_dirs = set()
154 + for x in set(dir_list):
155 + try:
156 + dev = os.stat(x).st_dev
157 + except OSError:
158 + pass
159 + else:
160 + if dev in ro_devs:
161 + ro_dirs.add(x)
162 +
163 + return ro_dirs
164
165
166 def empty_ro_checker(dir_list):
167 --
168 2.3.5