def is_debug(): if OS.is_android() \ or 'PATCHER_DEBUG' in os.environ \ and os.environ['PATCHER_DEBUG'] == 'true': return True else: return False
def extract(boot_image, output_dir, loki): global output, error, error_msg try: if not OS.is_android() and not debug.is_debug(): unlokibootimg.show_output = False unpackbootimg.show_output = False if loki: unlokibootimg.extract(boot_image, output_dir) else: unpackbootimg.extract(boot_image, output_dir) except Exception as e: error_msg = 'Failed to extract boot image' return None info = BootImageInfo() prefix = os.path.join(output_dir, os.path.split(boot_image)[1]) info.base = int(fileio.first_line(prefix + '-base'), 16) info.cmdline = fileio.first_line(prefix + '-cmdline') info.pagesize = int(fileio.first_line(prefix + '-pagesize')) os.remove(prefix + '-base') os.remove(prefix + '-cmdline') os.remove(prefix + '-pagesize') if os.path.exists(prefix + '-ramdisk_offset'): info.ramdisk_offset = int(fileio.first_line(prefix + '-ramdisk_offset'), 16) os.remove(prefix + '-ramdisk_offset') elif config.get_ramdisk_offset() is not None: # We need this for Loki'd boot images info.ramdisk_offset = int(config.get_ramdisk_offset(), 16) if os.path.exists(prefix + '-second_offset'): info.second_offset = int(fileio.first_line(prefix + '-second_offset'), 16) os.remove(prefix + '-second_offset') if os.path.exists(prefix + '-tags_offset'): info.tags_offset = int(fileio.first_line(prefix + '-tags_offset'), 16) os.remove(prefix + '-tags_offset') info.kernel = prefix + '-zImage' if os.path.exists(prefix + '-ramdisk.gz'): info.ramdisk = prefix + '-ramdisk.gz' elif os.path.exists(prefix + '-ramdisk.lz4'): info.ramdisk = prefix + '-ramdisk.lz4' if os.path.exists(prefix + '-second'): info.second = prefix + '-second' if os.path.exists(prefix + '-dt'): info.dt = prefix + '-dt' return info
def extract(boot_image, output_dir): try: if not OS.is_android() and not debug.is_debug(): unlokibootimg.show_output = False unpackbootimg.show_output = False if unlokibootimg.is_loki(boot_image): unlokibootimg.extract(boot_image, output_dir) else: unpackbootimg.extract(boot_image, output_dir) except (OSError, unlokibootimg.UnlokibootimgError, unpackbootimg.UnpackbootimgError) as e: raise ExtractError('Failed to extract boot image: ' + str(e)) info = BootImageInfo() prefix = os.path.join(output_dir, os.path.split(boot_image)[1]) info.base = int(fileio.first_line(prefix + '-base'), 16) info.cmdline = fileio.first_line(prefix + '-cmdline') info.pagesize = int(fileio.first_line(prefix + '-pagesize')) os.remove(prefix + '-base') os.remove(prefix + '-cmdline') os.remove(prefix + '-pagesize') if os.path.exists(prefix + '-ramdisk_offset'): info.ramdisk_offset = \ int(fileio.first_line(prefix + '-ramdisk_offset'), 16) os.remove(prefix + '-ramdisk_offset') if os.path.exists(prefix + '-second_offset'): info.second_offset = \ int(fileio.first_line(prefix + '-second_offset'), 16) os.remove(prefix + '-second_offset') if os.path.exists(prefix + '-tags_offset'): info.tags_offset = \ int(fileio.first_line(prefix + '-tags_offset'), 16) os.remove(prefix + '-tags_offset') info.kernel = prefix + '-zImage' if os.path.exists(prefix + '-ramdisk.gz'): info.ramdisk = prefix + '-ramdisk.gz' elif os.path.exists(prefix + '-ramdisk.lz4'): info.ramdisk = prefix + '-ramdisk.lz4' if os.path.exists(prefix + '-second'): info.second = prefix + '-second' if os.path.exists(prefix + '-dt'): info.dt = prefix + '-dt' return info
def patch_supported(file_info): if partconfig.id != 'primaryupgrade': ui.info('Detected ' + file_info.patchinfo.name) file_info.partconfig = partconfig patcher = Patcher.get_patcher_by_partconfig(file_info) newfile = patcher.start_patching() if not newfile: sys.exit(1) file_info.move_to_target(newfile) if not OS.is_android(): ui.info("Path: " + file_info.get_new_filename())
def start_patching(): file_info = fileinfo.FileInfo() file_info.filename = filename # file_info.device = 'jflte' patcher = SyncdaemonPatcher(file_info) newfile = patcher.start_patching() if not newfile: sys.exit(1) fileext = os.path.splitext(filename) base = fileext[0] + '_syncdaemon' targetfile = base + fileext[1] shutil.copyfile(newfile, targetfile) os.remove(newfile) if not OS.is_android(): ui.info("Path: " + targetfile)
def patch_zip(zip_file, file_info, partition_config): if new_ui: ui = new_ui else: ui = OS.ui if not OS.is_android(): ui.info('--- Please wait. This may take a while ---') files_to_patch = [] if type(file_info.patch) == str and file_info.patch != "": files_to_patch = patch.files_in_patch(file_info.patch) elif type(file_info.patch) == list: for i in file_info.patch: if type(i) == str and i != "": files_to_patch.extend(patch.files_in_patch(i)) if file_info.extract: temp = file_info.extract if type(temp) == str or callable(temp): temp = [temp] for i in temp: if callable(i): output = i() if type(output) == list: files_to_patch.extend(output) elif type(output) == str: files_to_patch.append(output) elif type(i) == list: files_to_patch.extend(i) elif type(i) == str: files_to_patch.append(i) tempdir = tempfile.mkdtemp() exit.remove_on_exit(tempdir) set_task('EXTRACTING_ZIP') ui.details('Loading zip file ...') z = zipfile.ZipFile(zip_file, 'r') for f in files_to_patch: ui.details("Extracting file to be patched: %s" % f) try: z.extract(f, path=tempdir) except: ui.failed('Failed to extract file: %s' % f) exit.exit(1) if file_info.has_boot_image: ui.details("Extracting boot image: %s" % file_info.bootimg) try: z.extract(file_info.bootimg, path=tempdir) except: ui.failed('Failed to extract file: %s' % file_info.bootimg) exit.exit(1) z.close() ui.clear() if file_info.has_boot_image: boot_image = os.path.join(tempdir, file_info.bootimg) new_boot_image = patch_boot_image(boot_image, file_info, partition_config) os.remove(boot_image) shutil.move(new_boot_image, boot_image) else: ui.info('No boot image to patch') set_task('PATCHING_FILES') shutil.copy(os.path.join(OS.patchdir, 'dualboot.sh'), tempdir) autopatcher.insert_partition_info(tempdir, 'dualboot.sh', partition_config) if file_info.patch: ui.details('Running patch functions ...') temp = file_info.patch if type(temp) == str or callable(temp): temp = [temp] for i in temp: if callable(i): i(tempdir, bootimg=file_info.bootimg, device_check=file_info.device_check, partition_config=partition_config) elif type(i) == list: for j in i: if not patch.apply_patch(j, tempdir): ui.failed(patch.error_msg) exit.exit(1) elif type(i) == str: if not patch.apply_patch(i, tempdir): ui.failed(patch.error_msg) exit.exit(1) set_task('COMPRESSING_ZIP_FILE') ui.details('Opening input and output zip files ...') # We can't avoid recompression, unfortunately # Only show progress for this stage on Android, since it's, by far, the # most time consuming part of the process new_zip_file = os.path.join(tempdir, 'complete.zip') z_input = zipfile.ZipFile(zip_file, 'r') z_output = zipfile.ZipFile(new_zip_file, 'w', zipfile.ZIP_DEFLATED) progress_current = 0 progress_total = len(z_input.infolist()) - len(files_to_patch) - 1 if file_info.has_boot_image: progress_total -= 1 for root, dirs, files in os.walk(tempdir): progress_total += len(files) ui.max_progress(progress_total) for i in z_input.infolist(): # Skip patched files if i.filename in files_to_patch: continue # Boot image too elif i.filename == file_info.bootimg: continue ui.details('Adding file to zip: %s' % i.filename) ui.progress() z_output.writestr(i.filename, z_input.read(i.filename)) ui.clear() z_input.close() for root, dirs, files in os.walk(tempdir): for f in files: if f == 'complete.zip': continue ui.details('Adding file to zip: %s' % f) ui.progress() arcdir = os.path.relpath(root, start=tempdir) z_output.write(os.path.join(root, f), arcname=os.path.join(arcdir, f)) ui.clear() z_output.close() return new_zip_file
file_info = fileinfo.FileInfo() file_info.set_filename(filename) file_info.set_device(config.get_device()) if not file_info.is_filetype_supported(): ui.failed('Unsupported file type') sys.exit(1) if not file_info.find_and_merge_patchinfo(): ui.failed('Unsupported file') sys.exit(1) if not file_info.is_partconfig_supported(partition_config): ui.info("The %s partition configuration is not supported for this file" % partition_config.id) sys.exit(1) file_info.set_partconfig(partition_config) newfile = patcher.patch_file(file_info) if not newfile: sys.exit(1) file_info.move_to_target(newfile) if not OS.is_android(): ui.info("Path: " + file_info.get_new_filename()) sys.exit(0)
def patch_zip(self): if not OS.is_android(): OS.ui.info('--- Please wait. This may take a while ---') tempdir = tempfile.mkdtemp() self.tempdirs.append(tempdir) OS.ui.set_task(self.tasks['EXTRACTING_ZIP']) OS.ui.details('Loading zip file ...') z = zipfile.ZipFile(self.file_info.filename, 'r') try: z.extract(UPDATER_SCRIPT, path=tempdir) except: OS.ui.failed('Failed to extract updater-script') return None z.close() OS.ui.clear() OS.ui.set_task(self.tasks['PATCHING_FILES']) lines = fileio.all_lines(os.path.join(tempdir, UPDATER_SCRIPT)) i = 0 i += autopatcher.insert_line( i, EXTRACT % (PERM_TOOL, '/tmp/' + PERM_TOOL), lines) i += autopatcher.insert_line( i, EXTRACT % ('dualboot.sh', '/tmp/dualboot.sh'), lines) i += autopatcher.insert_line(i, EXTRACT % ('setfacl', '/tmp/setfacl'), lines) i += autopatcher.insert_line(i, EXTRACT % ('setfattr', '/tmp/setfattr'), lines) i += autopatcher.insert_line(i, EXTRACT % ('getfacl', '/tmp/getfacl'), lines) i += autopatcher.insert_line(i, EXTRACT % ('getfattr', '/tmp/getfattr'), lines) i += autopatcher.insert_line(i, MAKE_EXECUTABLE % ('/tmp/' + PERM_TOOL), lines) i += autopatcher.insert_line(i, MAKE_EXECUTABLE % '/tmp/dualboot.sh', lines) i += autopatcher.insert_line(i, MAKE_EXECUTABLE % '/tmp/setfacl', lines) i += autopatcher.insert_line(i, MAKE_EXECUTABLE % '/tmp/setfattr', lines) i += autopatcher.insert_line(i, MAKE_EXECUTABLE % '/tmp/getfacl', lines) i += autopatcher.insert_line(i, MAKE_EXECUTABLE % '/tmp/getfattr', lines) i += autopatcher.insert_line(i, MOUNT % '/system', lines) i += autopatcher.insert_line(i, PERMS_BACKUP % '/system', lines) i += autopatcher.insert_line(i, UNMOUNT % '/system', lines) i += autopatcher.insert_line(i, MOUNT % '/cache', lines) i += autopatcher.insert_line(i, PERMS_BACKUP % '/cache', lines) i += autopatcher.insert_line(i, UNMOUNT % '/cache', lines) def insert_format_system(index, lines, mount): i = 0 if mount: i += autopatcher.insert_line(index + i, MOUNT % '/system', lines) i += autopatcher.insert_line(index + i, FORMAT_SYSTEM, lines) if mount: i += autopatcher.insert_line(index + i, UNMOUNT % '/system', lines) return i def insert_format_cache(index, lines, mount): i = 0 if mount: i += autopatcher.insert_line(index + i, MOUNT % '/cache', lines) i += autopatcher.insert_line(index + i, FORMAT_CACHE, lines) if mount: i += autopatcher.insert_line(index + i, UNMOUNT % '/cache', lines) return i psystem = config.get_partition(self.file_info.device, 'system') pcache = config.get_partition(self.file_info.device, 'cache') replaced_format_system = False replaced_format_cache = False i = 0 while i < len(lines): if re.search(r"^\s*format\s*\(.*$", lines[i]): if 'system' in lines[i] or (psystem and psystem in lines[i]): replaced_format_system = True del lines[i] i += insert_format_system(i, lines, True) elif 'cache' in lines[i] or (pcache and pcache in lines[i]): replaced_format_cache = True del lines[i] i += insert_format_cache(i, lines, True) else: i += 1 elif re.search(r'delete_recursive\s*\([^\)]*"/system"', lines[i]): replaced_format_system = True del lines[i] i += insert_format_system(i, lines, False) elif re.search(r'delete_recursive\s*\([^\)]*"/cache"', lines[i]): replaced_format_cache = True del lines[i] i += insert_format_cache(i, lines, False) else: i += 1 if not replaced_format_system and not replaced_format_cache: OS.ui.failed('The patcher could not find any /system or /cache' ' formatting lines in the updater-script file.\n\n' 'If the file is a ROM, then something failed. If the' ' file is not a ROM (eg. kernel or mod), it doesn\'t' ' need to be patched.') return None i += autopatcher.insert_line(i, MOUNT % '/system', lines) i += autopatcher.insert_line(i, PERMS_RESTORE % '/system', lines) i += autopatcher.insert_line(i, UNMOUNT % '/system', lines) i += autopatcher.insert_line(i, MOUNT % '/cache', lines) i += autopatcher.insert_line(i, PERMS_RESTORE % '/cache', lines) i += autopatcher.insert_line(i, UNMOUNT % '/cache', lines) i += autopatcher.insert_line( i, 'run_program("/tmp/dualboot.sh", "set-multi-kernel");', lines) fileio.write_lines(os.path.join(tempdir, UPDATER_SCRIPT), lines) shutil.copy(os.path.join(OS.patchdir, 'dualboot.sh'), tempdir) autopatcher.insert_partition_info(os.path.join(tempdir, 'dualboot.sh'), self.file_info.partconfig) OS.ui.set_task(self.tasks['COMPRESSING_ZIP_FILE']) OS.ui.details('Opening input and output zip files ...') # We can't avoid recompression, unfortunately # Only show progress for this stage on Android, since it's, by far, the # most time consuming part of the process new_zip_file = tempfile.mkstemp() z_input = zipfile.ZipFile(self.file_info.filename, 'r') z_output = zipfile.ZipFile(new_zip_file[1], 'w', zipfile.ZIP_DEFLATED) # Five extra files progress_total = len(z_input.infolist()) + 6 OS.ui.max_progress(progress_total) for i in z_input.infolist(): if i.filename == UPDATER_SCRIPT: continue OS.ui.details('Adding file to zip: %s' % i.filename) OS.ui.progress() in_info = z_input.getinfo(i.filename) z_output.writestr(in_info, z_input.read(in_info)) OS.ui.clear() z_input.close() OS.ui.details('Adding file to zip: ' + UPDATER_SCRIPT) OS.ui.progress() z_output.write(os.path.join(tempdir, UPDATER_SCRIPT), arcname=UPDATER_SCRIPT) OS.ui.details('Adding file to zip: ' + 'dualboot.sh') OS.ui.progress() z_output.write(os.path.join(tempdir, 'dualboot.sh'), arcname='dualboot.sh') for f in [PERM_TOOL, 'setfacl', 'setfattr', 'getfacl', 'getfattr']: OS.ui.details('Adding file to zip: ' + f) OS.ui.progress() z_output.write(os.path.join(OS.patchdir, f), arcname=f) OS.ui.clear() z_output.close() os.close(new_zip_file[0]) return new_zip_file[1]
def patch_zip(self): if not OS.is_android(): OS.ui.info('--- Please wait. This may take a while ---') ap_instances = [] files_to_patch = [] if self.file_info.patchinfo.autopatchers: for ap in self.file_info.patchinfo.autopatchers: if type(ap) == str: # Special case for patch files ap_instances.append(PatchFilePatcher(patchfile=ap)) # elif issubclass(ap, BasePatcher): elif True: ap_instances.append(ap()) else: raise ValueError('Invalid autopatcher type') for ap in ap_instances: for f in ap.files_list: if f not in files_to_patch: files_to_patch.append(f) tempdir = tempfile.mkdtemp() self.tempdirs.append(tempdir) OS.ui.set_task(self.tasks['EXTRACTING_ZIP']) OS.ui.details('Loading zip file ...') z = zipfile.ZipFile(self.file_info.filename, 'r') for f in files_to_patch: OS.ui.details("Extracting file to be patched: %s" % f) try: z.extract(f, path=tempdir) except: OS.ui.failed('Failed to extract file: %s' % f) return None bootimages = list() if self.file_info.patchinfo.has_boot_image: for i in self.file_info.patchinfo.bootimg: if callable(i): output = i(self.file_info.filename) if not output: continue if type(output) == list: bootimages.extend(output) elif type(output) == str: bootimages.append(output) else: bootimages.append(i) for bootimage in bootimages: OS.ui.details("Extracting boot image: %s" % bootimage) try: z.extract(bootimage, path=tempdir) except: OS.ui.failed('Failed to extract file: %s' % bootimage) return None z.close() OS.ui.clear() if self.file_info.patchinfo.has_boot_image: for bootimage in bootimages: bootimageold = os.path.join(tempdir, bootimage) bootimagenew = self.patch_boot_image(path=bootimageold) if not bootimagenew: return None os.remove(bootimageold) shutil.move(bootimagenew, bootimageold) else: OS.ui.info('No boot images to patch') OS.ui.set_task(self.tasks['PATCHING_FILES']) shutil.copy(os.path.join(OS.patchdir, 'dualboot.sh'), tempdir) autopatcher.insert_partition_info(os.path.join(tempdir, 'dualboot.sh'), self.file_info.partconfig) if ap_instances: OS.ui.details('Running autopatchers ...') for ap in ap_instances: ret = ap.patch(tempdir, self.file_info, bootimages=bootimages) # Auto patchers do not have to return anything if ret is False: OS.ui.failed(ap.error_msg) return None OS.ui.set_task(self.tasks['COMPRESSING_ZIP_FILE']) OS.ui.details('Opening input and output zip files ...') # We can't avoid recompression, unfortunately # Only show progress for this stage on Android, since it's, by far, the # most time consuming part of the process new_zip_file = tempfile.mkstemp() z_input = zipfile.ZipFile(self.file_info.filename, 'r') z_output = zipfile.ZipFile(new_zip_file[1], 'w', zipfile.ZIP_DEFLATED) progress_total = len(z_input.infolist()) - len(files_to_patch) if self.file_info.patchinfo.has_boot_image: progress_total -= len(bootimages) for root, dirs, files in os.walk(tempdir): progress_total += len(files) OS.ui.max_progress(progress_total) for i in z_input.infolist(): # Skip patched files if i.filename in files_to_patch: continue # Boot image too elif self.file_info.patchinfo.has_boot_image \ and i.filename in bootimages: continue OS.ui.details('Adding file to zip: %s' % i.filename) OS.ui.progress() in_info = z_input.getinfo(i.filename) z_output.writestr(in_info, z_input.read(in_info)) OS.ui.clear() z_input.close() for root, dirs, files in os.walk(tempdir): for f in files: OS.ui.details('Adding file to zip: %s' % f) OS.ui.progress() arcdir = os.path.relpath(root, start=tempdir) z_output.write(os.path.join(root, f), arcname=os.path.join(arcdir, f)) OS.ui.clear() z_output.close() os.close(new_zip_file[0]) return new_zip_file[1]
def patch_zip(self): if not OS.is_android(): OS.ui.info('--- Please wait. This may take a while ---') tempdir = tempfile.mkdtemp() self.tempdirs.append(tempdir) OS.ui.set_task(self.tasks['EXTRACTING_ZIP']) OS.ui.details('Loading zip file ...') z = zipfile.ZipFile(self.file_info.filename, 'r') try: z.extract(UPDATER_SCRIPT, path=tempdir) except: OS.ui.failed('Failed to extract updater-script') return None z.close() OS.ui.clear() OS.ui.set_task(self.tasks['PATCHING_FILES']) lines = fileio.all_lines(os.path.join(tempdir, UPDATER_SCRIPT)) i = 0 i += autopatcher.insert_line( i, EXTRACT % (PERM_TOOL, '/tmp/' + PERM_TOOL), lines) i += autopatcher.insert_line( i, EXTRACT % ('dualboot.sh', '/tmp/dualboot.sh'), lines) i += autopatcher.insert_line( i, EXTRACT % ('setfacl', '/tmp/setfacl'), lines) i += autopatcher.insert_line( i, EXTRACT % ('setfattr', '/tmp/setfattr'), lines) i += autopatcher.insert_line( i, EXTRACT % ('getfacl', '/tmp/getfacl'), lines) i += autopatcher.insert_line( i, EXTRACT % ('getfattr', '/tmp/getfattr'), lines) i += autopatcher.insert_line( i, MAKE_EXECUTABLE % ('/tmp/' + PERM_TOOL), lines) i += autopatcher.insert_line( i, MAKE_EXECUTABLE % '/tmp/dualboot.sh', lines) i += autopatcher.insert_line( i, MAKE_EXECUTABLE % '/tmp/setfacl', lines) i += autopatcher.insert_line( i, MAKE_EXECUTABLE % '/tmp/setfattr', lines) i += autopatcher.insert_line( i, MAKE_EXECUTABLE % '/tmp/getfacl', lines) i += autopatcher.insert_line( i, MAKE_EXECUTABLE % '/tmp/getfattr', lines) i += autopatcher.insert_line( i, MOUNT % '/system', lines) i += autopatcher.insert_line( i, PERMS_BACKUP % '/system', lines) i += autopatcher.insert_line( i, UNMOUNT % '/system', lines) i += autopatcher.insert_line( i, MOUNT % '/cache', lines) i += autopatcher.insert_line( i, PERMS_BACKUP % '/cache', lines) i += autopatcher.insert_line( i, UNMOUNT % '/cache', lines) def insert_format_system(index, lines, mount): i = 0 if mount: i += autopatcher.insert_line( index + i, MOUNT % '/system', lines) i += autopatcher.insert_line(index + i, FORMAT_SYSTEM, lines) if mount: i += autopatcher.insert_line( index + i, UNMOUNT % '/system', lines) return i def insert_format_cache(index, lines, mount): i = 0 if mount: i += autopatcher.insert_line( index + i, MOUNT % '/cache', lines) i += autopatcher.insert_line(index + i, FORMAT_CACHE, lines) if mount: i += autopatcher.insert_line( index + i, UNMOUNT % '/cache', lines) return i psystem = config.get_partition(self.file_info.device, 'system') pcache = config.get_partition(self.file_info.device, 'cache') replaced_format_system = False replaced_format_cache = False i = 0 while i < len(lines): if re.search(r"^\s*format\s*\(.*$", lines[i]): if 'system' in lines[i] or (psystem and psystem in lines[i]): replaced_format_system = True del lines[i] i += insert_format_system(i, lines, True) elif 'cache' in lines[i] or (pcache and pcache in lines[i]): replaced_format_cache = True del lines[i] i += insert_format_cache(i, lines, True) else: i += 1 elif re.search(r'delete_recursive\s*\([^\)]*"/system"', lines[i]): replaced_format_system = True del lines[i] i += insert_format_system(i, lines, False) elif re.search(r'delete_recursive\s*\([^\)]*"/cache"', lines[i]): replaced_format_cache = True del lines[i] i += insert_format_cache(i, lines, False) else: i += 1 if not replaced_format_system and not replaced_format_cache: OS.ui.failed('The patcher could not find any /system or /cache' ' formatting lines in the updater-script file.\n\n' 'If the file is a ROM, then something failed. If the' ' file is not a ROM (eg. kernel or mod), it doesn\'t' ' need to be patched.') return None i += autopatcher.insert_line( i, MOUNT % '/system', lines) i += autopatcher.insert_line( i, PERMS_RESTORE % '/system', lines) i += autopatcher.insert_line( i, UNMOUNT % '/system', lines) i += autopatcher.insert_line( i, MOUNT % '/cache', lines) i += autopatcher.insert_line( i, PERMS_RESTORE % '/cache', lines) i += autopatcher.insert_line( i, UNMOUNT % '/cache', lines) i += autopatcher.insert_line( i, 'run_program("/tmp/dualboot.sh", "set-multi-kernel");', lines) fileio.write_lines(os.path.join(tempdir, UPDATER_SCRIPT), lines) shutil.copy(os.path.join(OS.patchdir, 'dualboot.sh'), tempdir) autopatcher.insert_partition_info( os.path.join(tempdir, 'dualboot.sh'), self.file_info.partconfig) OS.ui.set_task(self.tasks['COMPRESSING_ZIP_FILE']) OS.ui.details('Opening input and output zip files ...') # We can't avoid recompression, unfortunately # Only show progress for this stage on Android, since it's, by far, the # most time consuming part of the process new_zip_file = tempfile.mkstemp() z_input = zipfile.ZipFile(self.file_info.filename, 'r') z_output = zipfile.ZipFile(new_zip_file[1], 'w', zipfile.ZIP_DEFLATED) # Five extra files progress_total = len(z_input.infolist()) + 6 OS.ui.max_progress(progress_total) for i in z_input.infolist(): if i.filename == UPDATER_SCRIPT: continue OS.ui.details('Adding file to zip: %s' % i.filename) OS.ui.progress() in_info = z_input.getinfo(i.filename) z_output.writestr(in_info, z_input.read(in_info)) OS.ui.clear() z_input.close() OS.ui.details('Adding file to zip: ' + UPDATER_SCRIPT) OS.ui.progress() z_output.write(os.path.join(tempdir, UPDATER_SCRIPT), arcname=UPDATER_SCRIPT) OS.ui.details('Adding file to zip: ' + 'dualboot.sh') OS.ui.progress() z_output.write(os.path.join(tempdir, 'dualboot.sh'), arcname='dualboot.sh') for f in [PERM_TOOL, 'setfacl', 'setfattr', 'getfacl', 'getfattr']: OS.ui.details('Adding file to zip: ' + f) OS.ui.progress() z_output.write(os.path.join(OS.patchdir, f), arcname=f) OS.ui.clear() z_output.close() os.close(new_zip_file[0]) return new_zip_file[1]
def patch_zip(self): if not OS.is_android(): OS.ui.info('--- Please wait. This may take a while ---') ap_instances = [] files_to_patch = [] if self.file_info.patchinfo.autopatchers: for ap in self.file_info.patchinfo.autopatchers: if type(ap) == str: # Special case for patch files ap_instances.append(PatchFilePatcher(patchfile=ap)) # elif issubclass(ap, BasePatcher): elif True: ap_instances.append(ap()) else: raise ValueError('Invalid autopatcher type') for ap in ap_instances: for f in ap.files_list: if f not in files_to_patch: files_to_patch.append(f) tempdir = tempfile.mkdtemp() self.tempdirs.append(tempdir) OS.ui.set_task(self.tasks['EXTRACTING_ZIP']) OS.ui.details('Loading zip file ...') z = zipfile.ZipFile(self.file_info.filename, 'r') for f in files_to_patch: OS.ui.details("Extracting file to be patched: %s" % f) try: z.extract(f, path=tempdir) except: OS.ui.failed('Failed to extract file: %s' % f) return None bootimages = list() if self.file_info.patchinfo.has_boot_image: for i in self.file_info.patchinfo.bootimg: if callable(i): output = i(self.file_info.filename) if not output: continue if type(output) == list: bootimages.extend(output) elif type(output) == str: bootimages.append(output) else: bootimages.append(i) for bootimage in bootimages: OS.ui.details("Extracting boot image: %s" % bootimage) try: z.extract(bootimage, path=tempdir) except: OS.ui.failed('Failed to extract file: %s' % bootimage) return None z.close() OS.ui.clear() if self.file_info.patchinfo.has_boot_image: for bootimage in bootimages: bootimageold = os.path.join(tempdir, bootimage) bootimagenew = self.patch_boot_image(path=bootimageold) if not bootimagenew: return None os.remove(bootimageold) shutil.move(bootimagenew, bootimageold) else: OS.ui.info('No boot images to patch') OS.ui.set_task(self.tasks['PATCHING_FILES']) shutil.copy(os.path.join(OS.patchdir, 'dualboot.sh'), tempdir) autopatcher.insert_partition_info( os.path.join(tempdir, 'dualboot.sh'), self.file_info.partconfig) if ap_instances: OS.ui.details('Running autopatchers ...') for ap in ap_instances: ret = ap.patch(tempdir, self.file_info, bootimages=bootimages) # Auto patchers do not have to return anything if ret is False: OS.ui.failed(ap.error_msg) return None OS.ui.set_task(self.tasks['COMPRESSING_ZIP_FILE']) OS.ui.details('Opening input and output zip files ...') # We can't avoid recompression, unfortunately # Only show progress for this stage on Android, since it's, by far, the # most time consuming part of the process new_zip_file = tempfile.mkstemp() z_input = zipfile.ZipFile(self.file_info.filename, 'r') z_output = zipfile.ZipFile(new_zip_file[1], 'w', zipfile.ZIP_DEFLATED) progress_total = len(z_input.infolist()) - len(files_to_patch) if self.file_info.patchinfo.has_boot_image: progress_total -= len(bootimages) for root, dirs, files in os.walk(tempdir): progress_total += len(files) OS.ui.max_progress(progress_total) for i in z_input.infolist(): # Skip patched files if i.filename in files_to_patch: continue # Boot image too elif self.file_info.patchinfo.has_boot_image \ and i.filename in bootimages: continue OS.ui.details('Adding file to zip: %s' % i.filename) OS.ui.progress() in_info = z_input.getinfo(i.filename) z_output.writestr(in_info, z_input.read(in_info)) OS.ui.clear() z_input.close() for root, dirs, files in os.walk(tempdir): for f in files: OS.ui.details('Adding file to zip: %s' % f) OS.ui.progress() arcdir = os.path.relpath(root, start=tempdir) z_output.write(os.path.join(root, f), arcname=os.path.join(arcdir, f)) OS.ui.clear() z_output.close() os.close(new_zip_file[0]) return new_zip_file[1]