2017-06-05 01:58:45 +00:00
|
|
|
"""
|
|
|
|
Copyright 2017 Oliver Smith
|
|
|
|
|
|
|
|
This file is part of pmbootstrap.
|
|
|
|
|
|
|
|
pmbootstrap is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
pmbootstrap is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with pmbootstrap. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
"""
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import tarfile
|
|
|
|
import tempfile
|
|
|
|
import filecmp
|
|
|
|
import shutil
|
|
|
|
|
|
|
|
|
2017-06-17 15:42:28 +00:00
|
|
|
def contents_diff(tar_a, tar_b, member_a, member_b, name):
|
2017-06-06 20:21:59 +00:00
|
|
|
# Extract both files
|
|
|
|
tars = [tar_a, tar_b]
|
|
|
|
members = [member_a, member_b]
|
|
|
|
temp_files = []
|
|
|
|
for i in range(2):
|
|
|
|
handle, path = tempfile.mkstemp("pmbootstrap")
|
|
|
|
handle = open(handle, "wb")
|
|
|
|
shutil.copyfileobj(tars[i].extractfile(members[i]), handle)
|
|
|
|
handle.close()
|
|
|
|
temp_files.append(path)
|
|
|
|
|
|
|
|
# Compare and delete
|
|
|
|
equal = filecmp.cmp(temp_files[0], temp_files[1], shallow=False)
|
|
|
|
for temp_file in temp_files:
|
|
|
|
os.remove(temp_file)
|
|
|
|
if equal:
|
2017-07-14 17:32:57 +00:00
|
|
|
logging.verbose("=> OK!")
|
2017-06-06 20:21:59 +00:00
|
|
|
else:
|
|
|
|
raise RuntimeError("File '" + name + "' is different!")
|
|
|
|
|
|
|
|
|
2017-06-17 15:42:28 +00:00
|
|
|
def contents_without_signature(tar, tar_name):
|
2017-06-15 20:28:39 +00:00
|
|
|
"""
|
|
|
|
The signature file name is always different.
|
|
|
|
This function raises an exception, when the number of signature
|
|
|
|
files in the archive is not 1.
|
|
|
|
:returns: a sorted list of all filenames inside the tar archive,
|
|
|
|
except for the signature file.
|
|
|
|
"""
|
|
|
|
names = tar.getnames()
|
|
|
|
found = False
|
|
|
|
ret = []
|
|
|
|
for name in names:
|
|
|
|
if name.startswith(".SIGN.RSA."):
|
|
|
|
if found:
|
|
|
|
raise RuntimeError("More than one signature file found"
|
|
|
|
" inside " + tar_name + ": " +
|
|
|
|
str(names))
|
|
|
|
else:
|
|
|
|
found = True
|
|
|
|
else:
|
|
|
|
ret.append(name)
|
|
|
|
|
|
|
|
if not found:
|
|
|
|
raise RuntimeError("No signature file found inside " +
|
|
|
|
tar_name + ": " + str(names))
|
|
|
|
return sorted(ret)
|
|
|
|
|
|
|
|
|
2017-06-17 15:42:28 +00:00
|
|
|
def apk(args, apk_a, apk_b):
|
2017-06-05 01:58:45 +00:00
|
|
|
with tarfile.open(apk_a, "r:gz") as tar_a:
|
|
|
|
with tarfile.open(apk_b, "r:gz") as tar_b:
|
|
|
|
# List of files must be the same
|
2017-06-17 15:42:28 +00:00
|
|
|
list_a = contents_without_signature(tar_a, apk_a)
|
|
|
|
list_b = contents_without_signature(tar_b, apk_b)
|
2017-06-05 01:58:45 +00:00
|
|
|
if list_a != list_b:
|
2017-06-15 20:28:39 +00:00
|
|
|
logging.info("Files in " + apk_a + ":" + str(list_a))
|
|
|
|
logging.info("Files in " + apk_b + ":" + str(list_b))
|
2017-06-05 01:58:45 +00:00
|
|
|
raise RuntimeError(
|
|
|
|
"Both APKs do not contain the same file names!")
|
|
|
|
|
|
|
|
# Iterate through the list
|
2017-06-06 20:21:59 +00:00
|
|
|
success = True
|
2017-06-05 01:58:45 +00:00
|
|
|
for name in list_a:
|
2017-06-06 20:21:59 +00:00
|
|
|
try:
|
2017-07-14 17:32:57 +00:00
|
|
|
logging.verbose("Compare: " + name)
|
2017-06-15 20:28:39 +00:00
|
|
|
if name == ".PKGINFO":
|
2017-07-14 17:32:57 +00:00
|
|
|
logging.verbose(
|
2017-06-16 23:58:40 +00:00
|
|
|
"=> Skipping: expected to be different")
|
2017-06-05 01:58:45 +00:00
|
|
|
continue
|
|
|
|
|
2017-06-06 20:21:59 +00:00
|
|
|
# Get members
|
|
|
|
member_a = tar_a.getmember(name)
|
|
|
|
member_b = tar_b.getmember(name)
|
|
|
|
if member_a.type != member_b.type:
|
|
|
|
raise RuntimeError(
|
|
|
|
"Entry '" + name + "' has a different type!")
|
|
|
|
|
|
|
|
if member_a.isdir():
|
2017-07-14 17:32:57 +00:00
|
|
|
logging.verbose("=> Skipping: directory")
|
2017-06-06 20:21:59 +00:00
|
|
|
elif member_a.isfile():
|
2017-06-17 15:42:28 +00:00
|
|
|
contents_diff(tar_a, tar_b, member_a, member_b, name)
|
2017-06-06 20:21:59 +00:00
|
|
|
elif member_a.issym() or member_a.islnk():
|
|
|
|
if member_a.linkname == member_b.linkname:
|
2017-07-14 17:32:57 +00:00
|
|
|
logging.verbose(
|
2017-06-06 20:21:59 +00:00
|
|
|
"=> Both link to " + member_a.linkname)
|
|
|
|
else:
|
|
|
|
raise RuntimeError(
|
|
|
|
"Link " + name + " has a different target!")
|
|
|
|
else:
|
|
|
|
raise RuntimeError(
|
|
|
|
"Can't diff '" + name + "', unsupported type!")
|
|
|
|
except Exception as e:
|
|
|
|
logging.info("CHALLENGE FAILED for " + name + ":" + str(e))
|
|
|
|
success = False
|
|
|
|
if not success:
|
|
|
|
raise RuntimeError("Challenge failed (see errors above)")
|