summaryrefslogtreecommitdiff
blob: 602572412e11b207233d15d7f2b22aa2b1fa65d6 (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
123
124
125
126
127
128
129
130
131
132
133
134
# portage_checksum.py -- core Portage functionality
# Copyright 1998-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id: /var/cvsroot/gentoo-src/portage/pym/portage_checksum.py,v 1.10.2.2 2005/08/10 05:42:03 ferringb Exp $
cvs_id_string="$Id: portage_checksum.py,v 1.10.2.2 2005/08/10 05:42:03 ferringb Exp $"[5:-2]

from portage_const import PRIVATE_PATH,PRELINK_BINARY
import os
import shutil
import stat
import portage_exec
import portage_util
import portage_locks
import commands
import sha

prelink_capable = False
if os.path.exists(PRELINK_BINARY):
	results = commands.getstatusoutput(PRELINK_BINARY+" --version > /dev/null 2>&1")
	if (results[0] >> 8) == 0:
		prelink_capable=1
	del results

def perform_md5(x, calc_prelink=0):
	return perform_checksum(x, md5hash, calc_prelink)[0]

def perform_sha1(x, calc_prelink=0):
	return perform_checksum(x, sha1hash, calc_prelink)[0]

def perform_all(x, calc_prelink=0):
	mydict = {}
	mydict["SHA1"] = perform_sha1(x, calc_prelink)
	mydict["MD5"] = perform_md5(x, calc_prelink)
	return mydict

def get_valid_checksum_keys():
	return ["SHA1", "MD5"]

def verify_all(filename, mydict, calc_prelink=0, strict=0):
	# Dict relates to single file only.
	# returns: (passed,reason)
	file_is_ok = True
	reason     = "Reason unknown"
	try:
		if mydict["size"] != os.stat(filename)[stat.ST_SIZE]:
			return False,"Filesize does not match recorded size"
	except OSError, e:
		return False, str(e)
	for x in mydict.keys():
		if   x == "size":
			continue
		elif x == "SHA1":
			if mydict[x] != perform_sha1(filename, calc_prelink=calc_prelink):
				if strict:
					raise portage_exception.DigestException, "Failed to verify '$(file)s' on checksum type '%(type)s'" % {"file":filename, "type":x}
				else:
					file_is_ok = False
					reason     = "Failed on %s verification" % (x,)
					break
		elif x == "MD5":
			if mydict[x] != perform_md5(filename, calc_prelink=calc_prelink):
				if strict:
					raise portage_exception.DigestException, "Failed to verify '$(file)s' on checksum type '%(type)s'" % {"file":filename, "type":x}
				else:
					file_is_ok = False
					reason     = "Failed on %s verification" % (x,)
					break
	return file_is_ok,reason

# We _try_ to load this module. If it fails we do the slow fallback.
try:
	import fchksum
	
	def md5hash(filename):
		return fchksum.fmd5t(filename)

except ImportError:
	import md5
	def md5hash(filename):
		f = open(filename, 'rb')
		blocksize=32768
		data = f.read(blocksize)
		size = 0L
		sum = md5.new()
		while data:
			sum.update(data)
			size = size + len(data)
			data = f.read(blocksize)
		f.close()

		return (sum.hexdigest(),size)

def sha1hash(filename):
	f = open(filename, 'rb')
	blocksize=32768
	data = f.read(blocksize)
	size = 0L
	sum = sha.new()
	while data:
		sum.update(data)
		size = size + len(data)
		data = f.read(blocksize)
	f.close()

	return (sum.hexdigest(),size)

def perform_checksum(filename, hash_function=md5hash, calc_prelink=0):
	myfilename      = filename[:]
	prelink_tmpfile = PRIVATE_PATH+"/prelink-checksum.tmp."+str(os.getpid())
	mylock          = None
	
	if calc_prelink and prelink_capable:
		mylock = portage_locks.lockfile(prelink_tmpfile, wantnewlockfile=1)
		# Create non-prelinked temporary file to md5sum.
		# Raw data is returned on stdout, errors on stderr.
		# Non-prelinks are just returned.
		try:
			shutil.copy2(filename,prelink_tmpfile)
		except SystemExit, e:
			raise
		except Exception,e:
			portage_util.writemsg("!!! Unable to copy file '"+str(filename)+"'.\n")
			portage_util.writemsg("!!! "+str(e)+"\n")
			raise
		portage_exec.spawn(PRELINK_BINARY+" --undo "+prelink_tmpfile,fd_pipes={})
		myfilename=prelink_tmpfile

	myhash, mysize = hash_function(myfilename)

	if calc_prelink and prelink_capable:
		os.unlink(prelink_tmpfile)
		portage_locks.unlockfile(mylock)

	return (myhash,mysize)