1 |
commit: accee1b7c61da284022f86d9ab39bcb492ea4023 |
2 |
Author: Zac Medico <zmedico <AT> gentoo <DOT> org> |
3 |
AuthorDate: Tue Aug 21 20:22:19 2012 +0000 |
4 |
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> |
5 |
CommitDate: Tue Aug 21 20:22:19 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=accee1b7 |
7 |
|
8 |
Implement PORTAGE_CHECKSUM_FILTER for bug #432170 |
9 |
|
10 |
--- |
11 |
man/make.conf.5 | 19 +++++++- |
12 |
pym/_emerge/EbuildFetcher.py | 4 +- |
13 |
pym/portage/checksum.py | 54 ++++++++++++++++++++ |
14 |
pym/portage/dbapi/bintree.py | 6 ++- |
15 |
pym/portage/manifest.py | 15 +++-- |
16 |
.../package/ebuild/_config/special_env_vars.py | 1 + |
17 |
pym/portage/package/ebuild/digestcheck.py | 13 +++-- |
18 |
pym/portage/package/ebuild/fetch.py | 13 +++-- |
19 |
8 files changed, 107 insertions(+), 18 deletions(-) |
20 |
|
21 |
diff --git a/man/make.conf.5 b/man/make.conf.5 |
22 |
index c617fbc..59f32b8 100644 |
23 |
--- a/man/make.conf.5 |
24 |
+++ b/man/make.conf.5 |
25 |
@@ -1,4 +1,4 @@ |
26 |
-.TH "MAKE.CONF" "5" "Jul 2012" "Portage VERSION" "Portage" |
27 |
+.TH "MAKE.CONF" "5" "Aug 2012" "Portage VERSION" "Portage" |
28 |
.SH "NAME" |
29 |
make.conf \- custom settings for Portage |
30 |
.SH "SYNOPSIS" |
31 |
@@ -697,6 +697,23 @@ for bzip2 compression operations. \fBPORTAGE_BZIP2_COMMAND\fR will also be |
32 |
called for extraction operation, with -d appended, unless the |
33 |
\fBPORTAGE_BUNZIP2_COMMAND\fR variable is set. |
34 |
.TP |
35 |
+\fBPORTAGE_CHECKSUM_FILTER\fR = \fI[space delimited list of hash names]\fR |
36 |
+This variable may be used to filter the hash functions that are used to |
37 |
+verify integrity of files. Hash functions names are case\-insensitive, and |
38 |
+the \fI*\fR and \fI\-*\fR wildcard tokens are supported. |
39 |
+.br |
40 |
+Defaults to the value of *. |
41 |
+.br |
42 |
+.I Examples: |
43 |
+.nf |
44 |
+# Use all available hash functions |
45 |
+PORTAGE_CHECKSUM_FILTER="*" |
46 |
+# Use any function except whirlpool |
47 |
+PORTAGE_CHECKSUM_FILTER="* \-whirlpool" |
48 |
+# Only use sha256 |
49 |
+PORTAGE_CHECKSUM_FILTER="\-* sha256" |
50 |
+.fi |
51 |
+.TP |
52 |
\fBPORTAGE_COMPRESS\fR = \fI"bzip2"\fR |
53 |
This variable contains the command used to compress documentation during the |
54 |
install phase. |
55 |
|
56 |
diff --git a/pym/_emerge/EbuildFetcher.py b/pym/_emerge/EbuildFetcher.py |
57 |
index c0a7fdd..bbcb6a9 100644 |
58 |
--- a/pym/_emerge/EbuildFetcher.py |
59 |
+++ b/pym/_emerge/EbuildFetcher.py |
60 |
@@ -13,6 +13,7 @@ from portage import os |
61 |
from portage import _encodings |
62 |
from portage import _unicode_encode |
63 |
from portage import _unicode_decode |
64 |
+from portage.checksum import _hash_filter |
65 |
from portage.elog.messages import eerror |
66 |
from portage.package.ebuild.fetch import _check_distfile, fetch |
67 |
from portage.util._pty import _create_pty_or_pipe |
68 |
@@ -57,6 +58,7 @@ class EbuildFetcher(SpawnProcess): |
69 |
if st.st_size != expected_size: |
70 |
return False |
71 |
|
72 |
+ hash_filter = _hash_filter(settings.get("PORTAGE_CHECKSUM_FILTER", "")) |
73 |
stdout_orig = sys.stdout |
74 |
stderr_orig = sys.stderr |
75 |
global_havecolor = portage.output.havecolor |
76 |
@@ -78,7 +80,7 @@ class EbuildFetcher(SpawnProcess): |
77 |
break |
78 |
continue |
79 |
ok, st = _check_distfile(os.path.join(distdir, filename), |
80 |
- mydigests, eout, show_errors=False) |
81 |
+ mydigests, eout, show_errors=False, hash_filter=hash_filter) |
82 |
if not ok: |
83 |
success = False |
84 |
break |
85 |
|
86 |
diff --git a/pym/portage/checksum.py b/pym/portage/checksum.py |
87 |
index daf4a0c..de4cc66 100644 |
88 |
--- a/pym/portage/checksum.py |
89 |
+++ b/pym/portage/checksum.py |
90 |
@@ -217,6 +217,60 @@ def _filter_unaccelarated_hashes(digests): |
91 |
|
92 |
return digests |
93 |
|
94 |
+class _hash_filter(object): |
95 |
+ """ |
96 |
+ Implements filtering for PORTAGE_CHECKSUM_FILTER. |
97 |
+ """ |
98 |
+ |
99 |
+ __slots__ = ('transparent', '_tokens',) |
100 |
+ |
101 |
+ def __init__(self, filter_str): |
102 |
+ tokens = filter_str.upper().split() |
103 |
+ if not tokens or tokens[-1] == "*": |
104 |
+ del tokens[:] |
105 |
+ self.transparent = not tokens |
106 |
+ tokens.reverse() |
107 |
+ self._tokens = tuple(tokens) |
108 |
+ |
109 |
+ def __call__(self, hash_name): |
110 |
+ if self.transparent: |
111 |
+ return True |
112 |
+ matches = ("*", hash_name) |
113 |
+ for token in self._tokens: |
114 |
+ if token in matches: |
115 |
+ return True |
116 |
+ elif token[:1] == "-": |
117 |
+ if token[1:] in matches: |
118 |
+ return False |
119 |
+ return False |
120 |
+ |
121 |
+def _apply_hash_filter(digests, hash_filter): |
122 |
+ """ |
123 |
+ Return a new dict containing the filtered digests, or the same |
124 |
+ dict if no changes are necessary. This will always preserve at |
125 |
+ at least one digest, in order to ensure that they are not all |
126 |
+ discarded. |
127 |
+ """ |
128 |
+ if hash_filter.transparent: |
129 |
+ return digests |
130 |
+ |
131 |
+ verifiable_hash_types = set(digests).intersection(hashfunc_map) |
132 |
+ verifiable_hash_types.discard("size") |
133 |
+ modified = False |
134 |
+ if len(verifiable_hash_types) > 1: |
135 |
+ for k in list(verifiable_hash_types): |
136 |
+ if not hash_filter(k): |
137 |
+ modified = True |
138 |
+ verifiable_hash_types.remove(k) |
139 |
+ if len(verifiable_hash_types) == 1: |
140 |
+ break |
141 |
+ |
142 |
+ if modified: |
143 |
+ digests = dict((k, v) for (k, v) in digests.items() |
144 |
+ if k == "size" or k in verifiable_hash_types) |
145 |
+ |
146 |
+ return digests |
147 |
+ |
148 |
def verify_all(filename, mydict, calc_prelink=0, strict=0): |
149 |
""" |
150 |
Verify all checksums against a file. |
151 |
|
152 |
diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py |
153 |
index 6c01867..a2fd5ea 100644 |
154 |
--- a/pym/portage/dbapi/bintree.py |
155 |
+++ b/pym/portage/dbapi/bintree.py |
156 |
@@ -5,7 +5,8 @@ __all__ = ["bindbapi", "binarytree"] |
157 |
|
158 |
import portage |
159 |
portage.proxy.lazyimport.lazyimport(globals(), |
160 |
- 'portage.checksum:hashfunc_map,perform_multiple_checksums,verify_all', |
161 |
+ 'portage.checksum:hashfunc_map,perform_multiple_checksums,' + \ |
162 |
+ 'verify_all,_apply_hash_filter,_hash_filter', |
163 |
'portage.dbapi.dep_expand:dep_expand', |
164 |
'portage.dep:dep_getkey,isjustname,isvalidatom,match_from_list', |
165 |
'portage.output:EOutput,colorize', |
166 |
@@ -1462,6 +1463,9 @@ class binarytree(object): |
167 |
if not digests: |
168 |
return False |
169 |
|
170 |
+ hash_filter = _hash_filter( |
171 |
+ self.settings.get("PORTAGE_CHECKSUM_FILTER", "")) |
172 |
+ digests = _apply_hash_filter(digests, hash_filter) |
173 |
eout = EOutput() |
174 |
eout.quiet = self.settings.get("PORTAGE_QUIET") == "1" |
175 |
ok, st = _check_distfile(pkg_path, digests, eout, show_errors=0) |
176 |
|
177 |
diff --git a/pym/portage/manifest.py b/pym/portage/manifest.py |
178 |
index a04b717..b2f1ff2 100644 |
179 |
--- a/pym/portage/manifest.py |
180 |
+++ b/pym/portage/manifest.py |
181 |
@@ -9,7 +9,7 @@ import warnings |
182 |
import portage |
183 |
portage.proxy.lazyimport.lazyimport(globals(), |
184 |
'portage.checksum:hashfunc_map,perform_multiple_checksums,' + \ |
185 |
- 'verify_all,_filter_unaccelarated_hashes', |
186 |
+ 'verify_all,_apply_hash_filter,_filter_unaccelarated_hashes', |
187 |
'portage.util:write_atomic', |
188 |
) |
189 |
|
190 |
@@ -502,14 +502,17 @@ class Manifest(object): |
191 |
for t in MANIFEST2_IDENTIFIERS: |
192 |
self.checkTypeHashes(t, ignoreMissingFiles=ignoreMissingFiles) |
193 |
|
194 |
- def checkTypeHashes(self, idtype, ignoreMissingFiles=False): |
195 |
+ def checkTypeHashes(self, idtype, ignoreMissingFiles=False, hash_filter=None): |
196 |
for f in self.fhashdict[idtype]: |
197 |
- self.checkFileHashes(idtype, f, ignoreMissing=ignoreMissingFiles) |
198 |
+ self.checkFileHashes(idtype, f, ignoreMissing=ignoreMissingFiles, |
199 |
+ hash_filter=hash_filter) |
200 |
|
201 |
- def checkFileHashes(self, ftype, fname, ignoreMissing=False): |
202 |
+ def checkFileHashes(self, ftype, fname, ignoreMissing=False, hash_filter=None): |
203 |
+ digests = _filter_unaccelarated_hashes(self.fhashdict[ftype][fname]) |
204 |
+ if hash_filter is not None: |
205 |
+ digests = _apply_hash_filter(digests, hash_filter) |
206 |
try: |
207 |
- ok, reason = verify_all(self._getAbsname(ftype, fname), |
208 |
- _filter_unaccelarated_hashes(self.fhashdict[ftype][fname])) |
209 |
+ ok, reason = verify_all(self._getAbsname(ftype, fname), digests) |
210 |
if not ok: |
211 |
raise DigestException(tuple([self._getAbsname(ftype, fname)]+list(reason))) |
212 |
return ok, reason |
213 |
|
214 |
diff --git a/pym/portage/package/ebuild/_config/special_env_vars.py b/pym/portage/package/ebuild/_config/special_env_vars.py |
215 |
index 6ed6d05..c974eb9 100644 |
216 |
--- a/pym/portage/package/ebuild/_config/special_env_vars.py |
217 |
+++ b/pym/portage/package/ebuild/_config/special_env_vars.py |
218 |
@@ -150,6 +150,7 @@ environ_filter += [ |
219 |
"PORTAGE_BACKGROUND", "PORTAGE_BACKGROUND_UNMERGE", |
220 |
"PORTAGE_BINHOST", |
221 |
"PORTAGE_BINHOST_CHUNKSIZE", "PORTAGE_BUILDIR_LOCKED", |
222 |
+ "PORTAGE_CHECKSUM_FILTER", |
223 |
"PORTAGE_ELOG_CLASSES", |
224 |
"PORTAGE_ELOG_MAILFROM", "PORTAGE_ELOG_MAILSUBJECT", |
225 |
"PORTAGE_ELOG_MAILURI", "PORTAGE_ELOG_SYSTEM", |
226 |
|
227 |
diff --git a/pym/portage/package/ebuild/digestcheck.py b/pym/portage/package/ebuild/digestcheck.py |
228 |
index 8705639..1d59948 100644 |
229 |
--- a/pym/portage/package/ebuild/digestcheck.py |
230 |
+++ b/pym/portage/package/ebuild/digestcheck.py |
231 |
@@ -1,4 +1,4 @@ |
232 |
-# Copyright 2010-2011 Gentoo Foundation |
233 |
+# Copyright 2010-2012 Gentoo Foundation |
234 |
# Distributed under the terms of the GNU General Public License v2 |
235 |
|
236 |
__all__ = ['digestcheck'] |
237 |
@@ -6,6 +6,7 @@ __all__ = ['digestcheck'] |
238 |
import warnings |
239 |
|
240 |
from portage import os, _encodings, _unicode_decode |
241 |
+from portage.checksum import _hash_filter |
242 |
from portage.exception import DigestException, FileNotFound |
243 |
from portage.localization import _ |
244 |
from portage.output import EOutput |
245 |
@@ -28,6 +29,7 @@ def digestcheck(myfiles, mysettings, strict=False, justmanifest=None, mf=None): |
246 |
if mysettings.get("EBUILD_SKIP_MANIFEST") == "1": |
247 |
return 1 |
248 |
pkgdir = mysettings["O"] |
249 |
+ hash_filter = _hash_filter(mysettings.get("PORTAGE_CHECKSUM_FILTER", "")) |
250 |
if mf is None: |
251 |
mf = mysettings.repositories.get_repo_for_location( |
252 |
os.path.dirname(os.path.dirname(pkgdir))) |
253 |
@@ -38,15 +40,16 @@ def digestcheck(myfiles, mysettings, strict=False, justmanifest=None, mf=None): |
254 |
if not mf.thin and strict and "PORTAGE_PARALLEL_FETCHONLY" not in mysettings: |
255 |
if mf.fhashdict.get("EBUILD"): |
256 |
eout.ebegin(_("checking ebuild checksums ;-)")) |
257 |
- mf.checkTypeHashes("EBUILD") |
258 |
+ mf.checkTypeHashes("EBUILD", hash_filter=hash_filter) |
259 |
eout.eend(0) |
260 |
if mf.fhashdict.get("AUX"): |
261 |
eout.ebegin(_("checking auxfile checksums ;-)")) |
262 |
- mf.checkTypeHashes("AUX") |
263 |
+ mf.checkTypeHashes("AUX", hash_filter=hash_filter) |
264 |
eout.eend(0) |
265 |
if mf.fhashdict.get("MISC"): |
266 |
eout.ebegin(_("checking miscfile checksums ;-)")) |
267 |
- mf.checkTypeHashes("MISC", ignoreMissingFiles=True) |
268 |
+ mf.checkTypeHashes("MISC", ignoreMissingFiles=True, |
269 |
+ hash_filter=hash_filter) |
270 |
eout.eend(0) |
271 |
for f in myfiles: |
272 |
eout.ebegin(_("checking %s ;-)") % f) |
273 |
@@ -58,7 +61,7 @@ def digestcheck(myfiles, mysettings, strict=False, justmanifest=None, mf=None): |
274 |
writemsg(_("\n!!! Missing digest for '%s'\n") % (f,), |
275 |
noiselevel=-1) |
276 |
return 0 |
277 |
- mf.checkFileHashes(ftype, f) |
278 |
+ mf.checkFileHashes(ftype, f, hash_filter=hash_filter) |
279 |
eout.eend(0) |
280 |
except FileNotFound as e: |
281 |
eout.eend(1) |
282 |
|
283 |
diff --git a/pym/portage/package/ebuild/fetch.py b/pym/portage/package/ebuild/fetch.py |
284 |
index 60ed04d..8365ad2 100644 |
285 |
--- a/pym/portage/package/ebuild/fetch.py |
286 |
+++ b/pym/portage/package/ebuild/fetch.py |
287 |
@@ -26,7 +26,7 @@ portage.proxy.lazyimport.lazyimport(globals(), |
288 |
from portage import OrderedDict, os, selinux, shutil, _encodings, \ |
289 |
_shell_quote, _unicode_encode |
290 |
from portage.checksum import (hashfunc_map, perform_md5, verify_all, |
291 |
- _filter_unaccelarated_hashes) |
292 |
+ _filter_unaccelarated_hashes, _hash_filter, _apply_hash_filter) |
293 |
from portage.const import BASH_BINARY, CUSTOM_MIRRORS_FILE, \ |
294 |
GLOBAL_CONFIG_PATH |
295 |
from portage.data import portage_gid, portage_uid, secpass, userpriv_groups |
296 |
@@ -185,7 +185,7 @@ def _check_digests(filename, digests, show_errors=1): |
297 |
return False |
298 |
return True |
299 |
|
300 |
-def _check_distfile(filename, digests, eout, show_errors=1): |
301 |
+def _check_distfile(filename, digests, eout, show_errors=1, hash_filter=None): |
302 |
""" |
303 |
@return a tuple of (match, stat_obj) where match is True if filename |
304 |
matches all given digests (if any) and stat_obj is a stat result, or |
305 |
@@ -212,6 +212,8 @@ def _check_distfile(filename, digests, eout, show_errors=1): |
306 |
return (False, st) |
307 |
else: |
308 |
digests = _filter_unaccelarated_hashes(digests) |
309 |
+ if hash_filter is not None: |
310 |
+ digests = _apply_hash_filter(digests, hash_filter) |
311 |
if _check_digests(filename, digests, show_errors=show_errors): |
312 |
eout.ebegin("%s %s ;-)" % (os.path.basename(filename), |
313 |
" ".join(sorted(digests)))) |
314 |
@@ -355,6 +357,7 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, |
315 |
if try_mirrors: |
316 |
mymirrors += [x.rstrip("/") for x in mysettings["GENTOO_MIRRORS"].split() if x] |
317 |
|
318 |
+ hash_filter = _hash_filter(mysettings.get("PORTAGE_CHECKSUM_FILTER", "")) |
319 |
skip_manifest = mysettings.get("EBUILD_SKIP_MANIFEST") == "1" |
320 |
if skip_manifest: |
321 |
allow_missing_digests = True |
322 |
@@ -637,7 +640,7 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, |
323 |
eout = EOutput() |
324 |
eout.quiet = mysettings.get("PORTAGE_QUIET") == "1" |
325 |
match, mystat = _check_distfile( |
326 |
- myfile_path, pruned_digests, eout) |
327 |
+ myfile_path, pruned_digests, eout, hash_filter=hash_filter) |
328 |
if match: |
329 |
# Skip permission adjustment for symlinks, since we don't |
330 |
# want to modify anything outside of the primary DISTDIR, |
331 |
@@ -709,7 +712,7 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, |
332 |
for x in ro_distdirs: |
333 |
filename = os.path.join(x, myfile) |
334 |
match, mystat = _check_distfile( |
335 |
- filename, pruned_digests, eout) |
336 |
+ filename, pruned_digests, eout, hash_filter=hash_filter) |
337 |
if match: |
338 |
readonly_file = filename |
339 |
break |
340 |
@@ -796,6 +799,7 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, |
341 |
continue |
342 |
else: |
343 |
digests = _filter_unaccelarated_hashes(mydigests[myfile]) |
344 |
+ digests = _apply_hash_filter(digests, hash_filter) |
345 |
verified_ok, reason = verify_all(myfile_path, digests) |
346 |
if not verified_ok: |
347 |
writemsg(_("!!! Previously fetched" |
348 |
@@ -1053,6 +1057,7 @@ def fetch(myuris, mysettings, listonly=0, fetchonly=0, |
349 |
# net connection. This way we have a chance to try to download |
350 |
# from another mirror... |
351 |
digests = _filter_unaccelarated_hashes(mydigests[myfile]) |
352 |
+ digests = _apply_hash_filter(digests, hash_filter) |
353 |
verified_ok, reason = verify_all(myfile_path, digests) |
354 |
if not verified_ok: |
355 |
writemsg(_("!!! Fetched file: %s VERIFY FAILED!\n") % myfile, |