1#!/usr/bin/env python
2
3#
4# Usage: fileDiffer <afile> <bfile> <list of disk changes>
5#
6
7# LUKS
8# quick regression test suite
9# Tests LUKS images for changes at certain disk offsets
10#
11# Does fast python code has to look ugly or is it just me?
12
13import sys
14
15class changes:
16	pass
17
18def parseArgs(args):
19	aFileName = args[1]
20	bFileName = args[2]
21	changelist = []
22	args[0:3] = []
23	for i in args:
24		mychanges = changes();
25		if i.startswith('A'):
26			mychanges.mode = 'ALLOWED'
27		if i.startswith('R'):
28			mychanges.mode = 'REQUIRED'
29			mychanges.strictness = 'RANDOM'
30		if i.startswith('S'):
31			mychanges.mode = 'REQUIRED'
32			mychanges.strictness = 'SEMANTIC'
33
34		dashIndex = i.find('-')
35		if dashIndex == -1:
36			mychanges.starts = int(i[1:])
37			mychanges.ends = mychanges.starts
38		else:
39			mychanges.starts = int(i[1:dashIndex])
40			mychanges.ends = int(i[dashIndex+1:])
41		mychanges.miss = 0
42		changelist.append(mychanges)
43	mychanges = changes();
44	mychanges.starts = 0
45#	mychanges.ends will be fixed later
46	mychanges.mode = 'FORBIDDEN'
47	changelist.append(mychanges)
48	return [aFileName, bFileName, changelist]
49
50def mode(i):
51	for c in changelist:
52		if i >= c.starts and i<=c.ends:
53			return c
54def cleanchanges(i):
55	newchangelist=[]
56	for c in changelist:
57		if i <= c.starts or i <= c.ends:
58			newchangelist.append(c)
59	return newchangelist
60
61[aFileName, bFileName, changelist] = parseArgs(sys.argv)
62
63aFile = open(aFileName,'r')
64bFile = open(bFileName,'r')
65
66aString = aFile.read()
67bString = bFile.read()
68
69if len(aString) != len(bString):
70	sys.exit("Mismatch different file sizes")
71
72fileLen = len(aString)
73fileLen10th = fileLen/10
74
75# Create a catch all entry
76changelist[-1].ends = fileLen
77
78print "Changes list: (FORBIDDEN default)"
79print "start\tend\tmode\t\tstrictness"
80for i in changelist:
81	if i.mode == 'REQUIRED':
82		print "%d\t%d\t%s\t%s" % (i.starts, i.ends, i.mode, i.strictness)
83	else:
84		print "%d\t%d\t%s" % (i.starts, i.ends, i.mode)
85
86
87filepos = 0
88fileLen10thC = 0
89print "[..........]"
90sys.stdout.write("[")
91sys.stdout.flush()
92
93modeNotTrivial = 1
94while filepos < fileLen:
95
96	if modeNotTrivial == 1:
97		c = mode(filepos)
98#	print (filepos, c.mode)
99	if c.mode == 'REQUIRED':
100		if aString[filepos] == bString[filepos]:
101			c.miss = c.miss + 1
102	else:
103		if aString[filepos] != bString[filepos] and c.mode != 'ALLOWED':
104			sys.exit("Mismatch at %d: change forbidden" % filepos)
105
106	# Do some maintaince, print progress bar, and clean changelist
107	#
108	# Maintaining two counters appears to be faster than modulo operation
109	if fileLen10thC == fileLen10th:
110		fileLen10thC = 0
111		sys.stdout.write(".")
112		sys.stdout.flush()
113		changelist = cleanchanges(filepos)
114		if len(changelist) == 1:
115			modeNotTrivial = 0
116	filepos = filepos + 1
117	fileLen10thC = fileLen10thC + 1
118
119for c in changelist:
120	if c.mode == 'REQUIRED':
121		if c.strictness == 'SEMANTIC' and c.miss == (c.ends-c.starts+1):
122			sys.exit("Mismatch: not even a single change in region %d-%d." % (c.starts, c.ends))
123   	        # This is not correct. We should do a statistical test
124	        # of the sampled data against the hypothetical distribution
125	        # of collision. Chi-Square Test.
126		if c.strictness == 'RANDOM' and c.miss == (c.ends-c.starts+1):
127			sys.exit("Mismatch: not even a single change in region %d-%d." % (c.starts, c.ends))
128
129print ".] - everything ok"
130