| # Copyright 1999-2019 Gentoo Authors |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| import errno |
| import io |
| import sys |
| |
| from _emerge.CompositeTask import CompositeTask |
| import portage |
| from portage import os |
| from portage.checksum import ( |
| _apply_hash_filter, |
| _filter_unaccelarated_hashes, |
| _hash_filter, |
| ) |
| from portage.output import EOutput |
| from portage.util._async.FileDigester import FileDigester |
| from portage.package.ebuild.fetch import _checksum_failure_temp_file |
| |
| |
| class BinpkgVerifier(CompositeTask): |
| __slots__ = ("logfile", "pkg", "_digests", "_pkg_path") |
| |
| def _start(self): |
| |
| bintree = self.pkg.root_config.trees["bintree"] |
| digests = bintree._get_digests(self.pkg) |
| if "size" not in digests: |
| self.returncode = os.EX_OK |
| self._async_wait() |
| return |
| |
| digests = _filter_unaccelarated_hashes(digests) |
| hash_filter = _hash_filter(bintree.settings.get("PORTAGE_CHECKSUM_FILTER", "")) |
| if not hash_filter.transparent: |
| digests = _apply_hash_filter(digests, hash_filter) |
| |
| self._digests = digests |
| |
| try: |
| size = os.stat(self._pkg_path).st_size |
| except OSError as e: |
| if e.errno not in (errno.ENOENT, errno.ESTALE): |
| raise |
| self.scheduler.output( |
| ("!!! Fetching Binary failed " "for '%s'\n") % self.pkg.cpv, |
| log_path=self.logfile, |
| background=self.background, |
| ) |
| self.returncode = 1 |
| self._async_wait() |
| return |
| else: |
| if size != digests["size"]: |
| self._digest_exception("size", size, digests["size"]) |
| self.returncode = 1 |
| self._async_wait() |
| return |
| |
| self._start_task( |
| FileDigester( |
| file_path=self._pkg_path, |
| hash_names=(k for k in digests if k != "size"), |
| background=self.background, |
| logfile=self.logfile, |
| scheduler=self.scheduler, |
| ), |
| self._digester_exit, |
| ) |
| |
| def _digester_exit(self, digester): |
| |
| if self._default_exit(digester) != os.EX_OK: |
| self.wait() |
| return |
| |
| for hash_name in digester.hash_names: |
| if digester.digests[hash_name] != self._digests[hash_name]: |
| self._digest_exception( |
| hash_name, digester.digests[hash_name], self._digests[hash_name] |
| ) |
| self.returncode = 1 |
| self.wait() |
| return |
| |
| if self.pkg.root_config.settings.get("PORTAGE_QUIET") != "1": |
| self._display_success() |
| |
| self.returncode = os.EX_OK |
| self.wait() |
| |
| def _display_success(self): |
| stdout_orig = sys.stdout |
| stderr_orig = sys.stderr |
| global_havecolor = portage.output.havecolor |
| out = io.StringIO() |
| try: |
| sys.stdout = out |
| sys.stderr = out |
| if portage.output.havecolor: |
| portage.output.havecolor = not self.background |
| |
| path = self._pkg_path |
| if path.endswith(".partial"): |
| path = path[: -len(".partial")] |
| eout = EOutput() |
| eout.ebegin( |
| "%s %s ;-)" % (os.path.basename(path), " ".join(sorted(self._digests))) |
| ) |
| eout.eend(0) |
| |
| finally: |
| sys.stdout = stdout_orig |
| sys.stderr = stderr_orig |
| portage.output.havecolor = global_havecolor |
| |
| self.scheduler.output( |
| out.getvalue(), log_path=self.logfile, background=self.background |
| ) |
| |
| def _digest_exception(self, name, value, expected): |
| |
| head, tail = os.path.split(self._pkg_path) |
| temp_filename = _checksum_failure_temp_file( |
| self.pkg.root_config.settings, head, tail |
| ) |
| |
| self.scheduler.output( |
| ( |
| "\n!!! Digest verification failed:\n" |
| "!!! %s\n" |
| "!!! Reason: Failed on %s verification\n" |
| "!!! Got: %s\n" |
| "!!! Expected: %s\n" |
| "File renamed to '%s'\n" |
| ) |
| % (self._pkg_path, name, value, expected, temp_filename), |
| log_path=self.logfile, |
| background=self.background, |
| ) |