Example #1
0
def is_debug():
    if OS.is_android() \
            or 'PATCHER_DEBUG' in os.environ \
            and os.environ['PATCHER_DEBUG'] == 'true':
        return True
    else:
        return False
Example #2
0
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
Example #3
0
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
Example #4
0
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)
Example #6
0
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
Example #7
0
    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)
Example #8
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]
Example #9
0
    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]
Example #10
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]
Example #11
0
    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]