# 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 $


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


# actual hash functions first

#dict of all available hash functions
hashfunc_map = {}

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

except ImportError:
	import md5
	def md5hash(filename):
		return pyhash(filename, md5)
hashfunc_map["MD5"] = md5hash

def sha1hash(filename):
	return pyhash(filename, sha)
hashfunc_map["SHA1"] = sha1hash
	
# Keep pycrypto optional for now, there are no internal fallbacks for these
try:
	import Crypto.Hash.SHA256
	
	def sha256hash(filename):
		return pyhash(filename, Crypto.Hash.SHA256)
	hashfunc_map["SHA256"] = sha256hash
except ImportError:
	pass

try:
	import Crypto.Hash.RIPEMD
	
	def rmd160hash(filename):
		return pyhash(filename, Crypto.Hash.RIPEMD)
	hashfunc_map["RMD160"] = rmd160hash
except ImportError:
	pass

def getsize(filename):
	size = os.stat(filename).st_size
	return (size, size)
hashfunc_map["size"] = getsize

# end actual hash functions

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, "MD5", calc_prelink)[0]

def perform_all(x, calc_prelink=0):
	mydict = {}
	for k in hashfunc_map.keys():
		mydict[k] = perform_checksum(x, hashfunc_map[k], calc_prelink)[0]
	return mydict

def get_valid_checksum_keys():
	return hashfunc_map.keys()

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:
		mysize = os.stat(filename)[stat.ST_SIZE]
		if mydict["size"] != mysize:
			return False,("Filesize does not match recorded size", mysize, mydict["size"])
	except OSError, e:
		if e.errno == errno.ENOENT:
			raise portage_exception.FileNotFound(filename)
		return False, (str(e), None, None)
	for x in mydict.keys():
		if   x == "size":
			continue
		elif x in hashfunc_map.keys():
			myhash = perform_checksum(filename, x, calc_prelink=calc_prelink)[0]
			if mydict[x] != myhash:
				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), myhash,mydict[x])
					break
	return file_is_ok,reason

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

	return (sum.hexdigest(), size)

def perform_checksum(filename, hashname="MD5", calc_prelink=0):
	myfilename      = filename[:]
	prelink_tmpfile = os.path.join("/", 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 checksum.
		# Files rejected by prelink are summed in place.
		retval=portage_exec.spawn([PRELINK_BINARY,"--undo","-o",prelink_tmpfile,filename],fd_pipes={})
		if retval==0:
			#portage_util.writemsg(">>> prelink checksum '"+str(filename)+"'.\n")
			myfilename=prelink_tmpfile
	try:
		if hashname not in hashfunc_map:
			raise portage_exception.DigestException, hashname+" hash function not available (needs dev-python/pycrypto)"
		myhash, mysize = hashfunc_map[hashname](myfilename)
	except (OSError, IOError), e:
		if e.errno == errno.ENOENT:
			raise portage_exception.FileNotFound(myfilename)
		else:
			raise e
	if calc_prelink and prelink_capable:
		try:
			os.unlink(prelink_tmpfile)
		except OSError, oe:
			if oe.errno == errno.ENOENT:
				pass
			else:
				raise oe
		portage_locks.unlockfile(mylock)

	return (myhash,mysize)

def perform_multiple_checksums(filename, hashes=["MD5"], calc_prelink=0):
	rVal = {}
	for x in hashes:
		if x not in hashfunc_map:
			raise portage_exception.DigestException, x+" hash function not available (needs dev-python/pycrypto)"
		rVal[x] = perform_checksum(filename, x, calc_prelink)[0]
	return rVal
