aboutsummaryrefslogtreecommitdiff
blob: f98f511a8852be3e8072fcd4c6224914b92b3bea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# 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)