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