#!/usr/bin/python3

# Python script to scan list of directories and generate SHA256 for each file in list
# the output may be used to compare 825 Gen2 patch builds and full microSD builds

import os
import sys
import hashlib
import platform

from os import stat
from pwd import getpwuid

# tupple of directories to scan, True/False show ownership and permissions, and for each directoy an array of directories to exclude from its scan
# We save space by only outputting the file ownership and permissions in directories containing files that are specific to the 825 Gen2
# [release] will be replaced with uname release such as '5.15.60-imx8mq+g65bed9ba6a65'

# Directory									Show ownership	Exclude directories
#											and permissions
dirlist = [ \
# Following directories contain files specific to 825 Gen2
('/usr/sbin/diag', 							True, 			[]), \
('/usr/sbin/card', 							True, 			[]), \
('/usr/sbin/util', 							True, 			[]), \
('/usr/images', 							True, 			[]), \
('/usr/share/fonts', 						True, 			[]), \
('/usr/share/apache2/default-site/htdocs', 	True, 			[]), \
('/etc/sudoers.d', 							True, 			[]), \
('/etc/xdg/weston',							True, 			[]), \
('/etc/apache2',							True, 			[]), \
('/lib/firmware', 							True, 			[]), \
('/lib/modules/[release]/extra', 			True, 			[]), \
('/boot', 									True, 			[]), \
# Following directories are more typical Variscite build files
('/usr/bin', 								False, 			['/usr/bin/onnxruntime-1.10.0', '/usr/bin/tensorflow-lite-2.9.1/examples']), \
('/usr/sbin', 								False, 			['/usr/sbin/diag', '/usr/sbin/card', '/usr/sbin/util']), \
('/usr/libexec', 							False, 			[]), \
('/usr/include', 							False, 			[]), \
('/usr/lib', 								False, 			[]), \
('/usr/share', 								False, 			['/usr/share/fonts','/usr/share/apache2/default-site/htdocs']), \
('/lib', 									False, 			['/lib/modules/[release]/extra','/lib/firmware']), \
('/opt', 									False, 			[]) \
]

BUF_SIZE = 65536

def get_hash(filepath):
	sha256 = hashlib.sha256()
	with open(filepath, 'rb') as f:
		while True:
			data = f.read(BUF_SIZE)
			if not data:
				break
			sha256.update(data)

	return sha256.hexdigest()

def hash_directory(start_path, showOwner, excludes):
	print(start_path)
	if excludes:
		#print('excludes ')
		for exclude in excludes:
			print('*exclude: ' + exclude)
	for root, dirs, files in os.walk(start_path):
		excluded = False
		for exclude in excludes:
			if(root[:len(exclude)] == exclude):
				#print('exclude dir')
				excluded = True
		if(excluded == False):
			if(root != start_path):
				print(root)
			files.sort()
			for file in files:
				filepath = os.path.join(root, file)
				if(os.access(filepath, os.R_OK)):
					hashVal = get_hash(filepath)
				else:
					hashVal = '----------------------READ-NOT-PERMITTED------------------------'
				if(showOwner):
					st = stat(filepath)
					modeOctal = oct(st.st_mode & 0o777)[2:]
					print("{0} {1} {2}:{3} {4}".format(hashVal, modeOctal, getpwuid(st.st_uid).pw_name, getpwuid(st.st_gid).pw_name, file))
				else:
					print("{0} {1}".format(hashVal, file))


if not os.geteuid() == 0:
    sys.exit("\nOnly root can run this script\n")

uname_release = platform.release()
print(uname_release)
print('SHA-256')
for filepath, showOwner, excludes in dirlist:
	filepath = filepath.replace('[release]', uname_release)
	ex = [sub.replace('[release]', uname_release) for sub in excludes]
	hash_directory(filepath, showOwner, ex)

