Esempio n. 1
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
Esempio n. 2
0
def patch_boot_image(boot_image, file_info, partition_config):
    if new_ui:
        ui = new_ui
    else:
        ui = OS.ui

    set_task('PATCHING_RAMDISK')

    tempdir = tempfile.mkdtemp()
    exit.remove_on_exit(tempdir)

    if file_info.loki:
        ui.details('Unpacking loki boot image ...')
    else:
        ui.details('Unpacking boot image ...')

    bootimageinfo = bootimage.extract(boot_image, tempdir, file_info.loki)
    if not bootimageinfo:
        ui.failed(bootimage.error_msg)
        exit.exit(1)

    selinux = config.get_selinux()
    if selinux is not None:
        bootimageinfo.cmdline += ' androidboot.selinux=' + selinux

    target_ramdisk = os.path.join(tempdir, 'ramdisk.cpio')
    target_kernel = os.path.join(tempdir, 'kernel.img')

    shutil.move(bootimageinfo.kernel, target_kernel)

    extracted = os.path.join(tempdir, 'extracted')
    os.mkdir(extracted)

    # Decompress ramdisk
    ui.details('Extracting ramdisk using cpio ...')
    with gzip.open(bootimageinfo.ramdisk, 'rb') as f_in:
        if not cpio.extract(extracted, data=f_in.read()):
            ui.command_error(output=cpio.output, error=cpio.error)
            ui.failed('Failed to extract ramdisk using cpio')
            exit.exit(1)

    os.remove(bootimageinfo.ramdisk)

    # Patch ramdisk
    if not file_info.ramdisk:
        ui.info('No ramdisk patch specified')
        return None

    ui.details('Modifying ramdisk ...')

    ramdisk.process_def(
        os.path.join(OS.ramdiskdir, file_info.ramdisk),
        extracted,
        partition_config
    )

    # Copy init.multiboot.mounting.sh
    shutil.copy(
        os.path.join(OS.ramdiskdir, 'init.multiboot.mounting.sh'),
        extracted
    )
    autopatcher.insert_partition_info(
        extracted, 'init.multiboot.mounting.sh',
        partition_config, target_path_only=True
    )

    # Copy busybox
    shutil.copy(
        os.path.join(OS.ramdiskdir, 'busybox-static'),
        os.path.join(extracted, 'sbin')
    )

    # Copy new init if needed
    if file_info.need_new_init:
        shutil.copy(
            os.path.join(OS.ramdiskdir, 'init'),
            extracted
        )

    # Create gzip compressed ramdisk
    set_task('COMPRESSING_RAMDISK')
    ramdisk_files = []
    for root, dirs, files in os.walk(extracted):
        for d in dirs:
            if os.path.samefile(root, extracted):
                # cpio, for whatever reason, creates a directory called '.'

                ramdisk_files.append(fileio.unix_path(d))

                ui.details('Adding directory to ramdisk: %s' % d)
            else:
                relative_dir = os.path.relpath(root, extracted)

                ramdisk_files.append(fileio.unix_path(
                    os.path.join(relative_dir, d)))

                ui.details('Adding directory to ramdisk: %s'
                           % os.path.join(relative_dir, d))

        for f in files:
            if os.path.samefile(root, extracted):
                # cpio, for whatever reason, creates a directory called '.'

                ramdisk_files.append(fileio.unix_path(f))

                ui.details('Adding file to ramdisk: %s' % f)
            else:
                relative_dir = os.path.relpath(root, extracted)

                ramdisk_files.append(fileio.unix_path(
                    os.path.join(relative_dir, f)))

                ui.details('Adding file to ramdisk: %s'
                           % os.path.join(relative_dir, f))

    ui.details('Creating gzip compressed ramdisk with cpio ...')

    target_ramdisk = target_ramdisk + ".gz"

    with gzip.open(target_ramdisk, 'wb') as f_out:
        data = cpio.create(extracted, ramdisk_files)

        if data is not None:
            f_out.write(data)
        else:
            ui.command_error(output=cpio.output, error=cpio.error)
            ui.failed('Failed to create gzip compressed ramdisk')
            exit.exit(1)

    set_task('CREATING_BOOT_IMAGE')
    ui.details('Running mkbootimg ...')

    bootimageinfo.kernel = target_kernel
    bootimageinfo.ramdisk = target_ramdisk

    if not bootimage.create(bootimageinfo,
                            os.path.join(tempdir, 'complete.img')):
        ui.failed('Failed to create boot image: ' + bootimage.error_msg)
        exit.exit(1)

    os.remove(target_kernel)
    os.remove(target_ramdisk)

    return os.path.join(tempdir, 'complete.img')
Esempio n. 3
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]
Esempio n. 4
0
    def patch_boot_image(self):
        path = self.file_info.filename

        OS.ui.set_task(self.tasks['PATCHING_RAMDISK'])

        tempdir = tempfile.mkdtemp()
        self.tempdirs.append(tempdir)

        OS.ui.details('Unpacking boot image ...')

        try:
            bootimageinfo = bootimage.extract(path, tempdir)
        except bootimage.ExtractError as e:
            OS.ui.failed(str(e))
            return None

        target_ramdisk = os.path.join(tempdir, 'ramdisk.cpio')

        # Minicpio
        OS.ui.details('Loading ramdisk with minicpio ...')
        cf = minicpio.CpioFile()
        with gzip.open(bootimageinfo.ramdisk, 'rb') as f:
            cf.load(f.read())

        os.remove(bootimageinfo.ramdisk)

        OS.ui.details('Modifying ramdisk ...')

        # Update
        partconfig = self.find_partconfig(cf)

        if partconfig and cf.get_file('init.multiboot.mounting.sh'):
            temp = tempfile.mkstemp()

            shutil.copyfile(
                os.path.join(OS.ramdiskdir, 'init.multiboot.mounting.sh'),
                temp[1])

            autopatcher.insert_partition_info(temp[1],
                                              partconfig,
                                              target_path_only=True)

            cf.add_file(temp[1],
                        name='init.multiboot.mounting.sh',
                        perms=0o750)

            os.close(temp[0])
            os.remove(temp[1])

        # Add syncdaemon to init.rc if it doesn't already exist
        if not cf.get_file('sbin/syncdaemon'):
            common.add_syncdaemon(cf)
        else:
            # Make sure 'oneshot' (added by previous versions) is removed
            initrc = cf.get_file('init.rc')
            lines = fileio.bytes_to_lines(initrc.content)
            buf = bytes()

            in_syncdaemon = False

            for line in lines:
                if line.startswith('service'):
                    in_syncdaemon = '/sbin/syncdaemon' in line
                    buf += fileio.encode(line)

                elif in_syncdaemon and 'oneshot' in line:
                    continue

                else:
                    buf += fileio.encode(line)

            initrc.content = buf

        # Copy syncdaemon
        cf.add_file(os.path.join(OS.ramdiskdir, 'syncdaemon'),
                    name='sbin/syncdaemon',
                    perms=0o750)

        # Create gzip compressed ramdisk
        OS.ui.details('Creating gzip compressed ramdisk with minicpio ...')

        target_ramdisk = target_ramdisk + ".gz"

        with gzip.open(target_ramdisk, 'wb') as f_out:
            data = cf.create()

            if data is not None:
                f_out.write(data)
            else:
                OS.ui.failed('Failed to create gzip compressed ramdisk')
                return None

        OS.ui.details('Running mkbootimg ...')

        bootimageinfo.ramdisk = target_ramdisk

        new_boot_image = tempfile.mkstemp()

        try:
            bootimage.create(bootimageinfo, new_boot_image[1])
        except bootimage.CreateError as e:
            OS.ui.failed('Failed to create boot image: ' + str(e))
            os.close(new_boot_image[0])
            os.remove(new_boot_image[1])
            return None

        os.remove(target_ramdisk)

        os.close(new_boot_image[0])
        return new_boot_image[1]
Esempio n. 5
0
    def patch_boot_image(self, path=None):
        if not path:
            path = self.file_info.filename

        OS.ui.set_task(self.tasks['PATCHING_RAMDISK'])

        tempdir = tempfile.mkdtemp()
        self.tempdirs.append(tempdir)

        OS.ui.details('Unpacking boot image ...')

        try:
            bootimageinfo = bootimage.extract(path, tempdir)
        except bootimage.ExtractError as e:
            OS.ui.failed(str(e))
            return None

        selinux = config.get_selinux(self.file_info.device)
        if selinux is not None:
            bootimageinfo.cmdline += ' androidboot.selinux=' + selinux

        target_ramdisk = os.path.join(tempdir, 'ramdisk.cpio')
        target_kernel = os.path.join(tempdir, 'kernel.img')

        shutil.move(bootimageinfo.kernel, target_kernel)

        # Minicpio
        OS.ui.details('Loading ramdisk with minicpio ...')
        cf = minicpio.CpioFile()
        with gzip.open(bootimageinfo.ramdisk, 'rb') as f:
            cf.load(f.read())

        os.remove(bootimageinfo.ramdisk)

        # Patch ramdisk
        if not self.file_info.patchinfo.ramdisk:
            OS.ui.info('No ramdisk patch specified')
            return None

        OS.ui.details('Modifying ramdisk ...')

        try:
            ramdisk.process_def(
                os.path.join(OS.ramdiskdir, self.file_info.patchinfo.ramdisk),
                cf, self.file_info.partconfig)
        except ramdisk.RamdiskPatchError as e:
            OS.ui.failed('Failed to patch ramdisk: ' + str(e))
            return None

        # Copy init.multiboot.mounting.sh
        shutil.copy(os.path.join(OS.ramdiskdir, 'init.multiboot.mounting.sh'),
                    tempdir)
        autopatcher.insert_partition_info(os.path.join(
            tempdir, 'init.multiboot.mounting.sh'),
                                          self.file_info.partconfig,
                                          target_path_only=True)
        cf.add_file(os.path.join(tempdir, 'init.multiboot.mounting.sh'),
                    name='init.multiboot.mounting.sh',
                    perms=0o750)
        os.remove(os.path.join(tempdir, 'init.multiboot.mounting.sh'))

        # Copy busybox
        cf.add_file(os.path.join(OS.ramdiskdir, 'busybox-static'),
                    name='sbin/busybox-static',
                    perms=0o750)

        # Copy syncdaemon
        cf.add_file(os.path.join(OS.ramdiskdir, 'syncdaemon'),
                    name='sbin/syncdaemon',
                    perms=0o750)

        # Copy patched init if needed
        if self.file_info.patchinfo.patched_init is not None:
            cf.add_file(os.path.join(OS.ramdiskdir, 'init',
                                     self.file_info.patchinfo.patched_init),
                        name='init',
                        perms=0o755)

        # Create gzip compressed ramdisk
        OS.ui.details('Creating gzip compressed ramdisk with minicpio ...')

        target_ramdisk = target_ramdisk + ".gz"

        with gzip.open(target_ramdisk, 'wb') as f_out:
            data = cf.create()

            if data is not None:
                f_out.write(data)
            else:
                OS.ui.failed('Failed to create gzip compressed ramdisk')
                return None

        OS.ui.details('Running mkbootimg ...')

        bootimageinfo.kernel = target_kernel
        bootimageinfo.ramdisk = target_ramdisk

        new_boot_image = tempfile.mkstemp()

        try:
            bootimage.create(bootimageinfo, new_boot_image[1])
        except bootimage.CreateError as e:
            OS.ui.failed('Failed to create boot image: ' + str(e))
            os.close(new_boot_image[0])
            os.remove(new_boot_image[1])
            return None

        os.remove(target_kernel)
        os.remove(target_ramdisk)

        os.close(new_boot_image[0])
        return new_boot_image[1]
Esempio n. 6
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]
Esempio n. 7
0
def patch_boot_image(file_info, path=None):
    # If file_info represents a boot image
    if not path:
        path = file_info._filename

    tempdirs = list()

    if new_ui:
        ui = new_ui
    else:
        ui = OS.ui

    set_task('PATCHING_RAMDISK')

    tempdir = tempfile.mkdtemp()
    tempdirs.append(tempdir)

    if file_info.loki:
        ui.details('Unpacking loki boot image ...')
    else:
        ui.details('Unpacking boot image ...')

    bootimageinfo = bootimage.extract(path, tempdir, file_info.loki)
    if not bootimageinfo:
        ui.failed(bootimage.error_msg)
        cleanup(tempdirs)
        return None

    selinux = config.get_selinux()
    if selinux is not None:
        bootimageinfo.cmdline += ' androidboot.selinux=' + selinux

    target_ramdisk = os.path.join(tempdir, 'ramdisk.cpio')
    target_kernel = os.path.join(tempdir, 'kernel.img')

    shutil.move(bootimageinfo.kernel, target_kernel)

    # Minicpio
    ui.details('Loading ramdisk with minicpio ...')
    cf = minicpio.CpioFile()
    with gzip.open(bootimageinfo.ramdisk, 'rb') as f:
        cf.load(f.read())

    os.remove(bootimageinfo.ramdisk)

    # Patch ramdisk
    if not file_info.ramdisk:
        ui.info('No ramdisk patch specified')
        return None

    ui.details('Modifying ramdisk ...')

    ramdisk.process_def(
        os.path.join(OS.ramdiskdir, file_info.ramdisk),
        cf,
        file_info._partconfig
    )

    # Copy init.multiboot.mounting.sh
    shutil.copy(
        os.path.join(OS.ramdiskdir, 'init.multiboot.mounting.sh'),
        tempdir
    )
    autopatcher.insert_partition_info(
        tempdir, 'init.multiboot.mounting.sh',
        file_info._partconfig, target_path_only=True
    )
    cf.add_file(
        os.path.join(tempdir, 'init.multiboot.mounting.sh'),
        name='init.multiboot.mounting.sh',
        perms=0o750
    )
    os.remove(os.path.join(tempdir, 'init.multiboot.mounting.sh'))

    # Copy busybox
    cf.add_file(
        os.path.join(OS.ramdiskdir, 'busybox-static'),
        name='sbin/busybox-static',
        perms=0o750
    )

    # Copy patched init if needed
    if file_info.patched_init is not None:
        cf.add_file(
            os.path.join(OS.ramdiskdir, 'init', file_info.patched_init),
            name='init',
            perms=0o755
        )

    # Create gzip compressed ramdisk
    set_task('COMPRESSING_RAMDISK')
    ui.details('Creating gzip compressed ramdisk with minicpio ...')

    target_ramdisk = target_ramdisk + ".gz"

    with gzip.open(target_ramdisk, 'wb') as f_out:
        data = cf.create()

        if data is not None:
            f_out.write(data)
        else:
            ui.failed('Failed to create gzip compressed ramdisk')
            cleanup(tempdirs)
            return None

    set_task('CREATING_BOOT_IMAGE')
    ui.details('Running mkbootimg ...')

    bootimageinfo.kernel = target_kernel
    bootimageinfo.ramdisk = target_ramdisk

    new_boot_image = tempfile.mkstemp()

    if not bootimage.create(bootimageinfo, new_boot_image[1]):
        ui.failed('Failed to create boot image: ' + bootimage.error_msg)
        cleanup(tempdirs)
        os.close(new_boot_image[0])
        os.remove(new_boot_image[1])
        return None

    os.remove(target_kernel)
    os.remove(target_ramdisk)

    cleanup(tempdirs)
    os.close(new_boot_image[0])
    return new_boot_image[1]
Esempio n. 8
0
    def patch_boot_image(self):
        path = self.file_info.filename

        OS.ui.set_task(self.tasks['PATCHING_RAMDISK'])

        tempdir = tempfile.mkdtemp()
        self.tempdirs.append(tempdir)

        OS.ui.details('Unpacking boot image ...')

        try:
            bootimageinfo = bootimage.extract(path, tempdir)
        except bootimage.ExtractError as e:
            OS.ui.failed(str(e))
            return None

        target_ramdisk = os.path.join(tempdir, 'ramdisk.cpio')

        # Minicpio
        OS.ui.details('Loading ramdisk with minicpio ...')
        cf = minicpio.CpioFile()
        with gzip.open(bootimageinfo.ramdisk, 'rb') as f:
            cf.load(f.read())

        os.remove(bootimageinfo.ramdisk)

        OS.ui.details('Modifying ramdisk ...')

        # Update
        partconfig = self.find_partconfig(cf)

        if partconfig and cf.get_file('init.multiboot.mounting.sh'):
            temp = tempfile.mkstemp()

            shutil.copyfile(
                os.path.join(OS.ramdiskdir, 'init.multiboot.mounting.sh'),
                temp[1]
            )

            autopatcher.insert_partition_info(
                temp[1], partconfig, target_path_only=True
            )

            cf.add_file(temp[1], name='init.multiboot.mounting.sh',
                        perms=0o750)

            os.close(temp[0])
            os.remove(temp[1])

        # Add syncdaemon to init.rc if it doesn't already exist
        if not cf.get_file('sbin/syncdaemon'):
            common.add_syncdaemon(cf)
        else:
            # Make sure 'oneshot' (added by previous versions) is removed
            initrc = cf.get_file('init.rc')
            lines = fileio.bytes_to_lines(initrc.content)
            buf = bytes()

            in_syncdaemon = False

            for line in lines:
                if line.startswith('service'):
                    in_syncdaemon = '/sbin/syncdaemon' in line
                    buf += fileio.encode(line)

                elif in_syncdaemon and 'oneshot' in line:
                    continue

                else:
                    buf += fileio.encode(line)

            initrc.content = buf


        # Copy syncdaemon
        cf.add_file(
            os.path.join(OS.ramdiskdir, 'syncdaemon'),
            name='sbin/syncdaemon',
            perms=0o750
        )

        # Create gzip compressed ramdisk
        OS.ui.details('Creating gzip compressed ramdisk with minicpio ...')

        target_ramdisk = target_ramdisk + ".gz"

        with gzip.open(target_ramdisk, 'wb') as f_out:
            data = cf.create()

            if data is not None:
                f_out.write(data)
            else:
                OS.ui.failed('Failed to create gzip compressed ramdisk')
                return None

        OS.ui.details('Running mkbootimg ...')

        bootimageinfo.ramdisk = target_ramdisk

        new_boot_image = tempfile.mkstemp()

        try:
            bootimage.create(bootimageinfo, new_boot_image[1])
        except bootimage.CreateError as e:
            OS.ui.failed('Failed to create boot image: ' + str(e))
            os.close(new_boot_image[0])
            os.remove(new_boot_image[1])
            return None

        os.remove(target_ramdisk)

        os.close(new_boot_image[0])
        return new_boot_image[1]
Esempio n. 9
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]
Esempio n. 10
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]
Esempio n. 11
0
    def patch_boot_image(self, path=None):
        if not path:
            path = self.file_info.filename

        OS.ui.set_task(self.tasks['PATCHING_RAMDISK'])

        tempdir = tempfile.mkdtemp()
        self.tempdirs.append(tempdir)

        OS.ui.details('Unpacking boot image ...')

        try:
            bootimageinfo = bootimage.extract(path, tempdir)
        except bootimage.ExtractError as e:
            OS.ui.failed(str(e))
            return None

        selinux = config.get_selinux(self.file_info.device)
        if selinux is not None:
            bootimageinfo.cmdline += ' androidboot.selinux=' + selinux

        target_ramdisk = os.path.join(tempdir, 'ramdisk.cpio')
        target_kernel = os.path.join(tempdir, 'kernel.img')

        shutil.move(bootimageinfo.kernel, target_kernel)

        # Minicpio
        OS.ui.details('Loading ramdisk with minicpio ...')
        cf = minicpio.CpioFile()
        with gzip.open(bootimageinfo.ramdisk, 'rb') as f:
            cf.load(f.read())

        os.remove(bootimageinfo.ramdisk)

        # Patch ramdisk
        if not self.file_info.patchinfo.ramdisk:
            OS.ui.info('No ramdisk patch specified')
            return None

        OS.ui.details('Modifying ramdisk ...')

        try:
            ramdisk.process_def(
                os.path.join(OS.ramdiskdir, self.file_info.patchinfo.ramdisk),
                cf,
                self.file_info.partconfig
            )
        except ramdisk.RamdiskPatchError as e:
            OS.ui.failed('Failed to patch ramdisk: ' + str(e))
            return None

        # Copy init.multiboot.mounting.sh
        shutil.copy(
            os.path.join(OS.ramdiskdir, 'init.multiboot.mounting.sh'),
            tempdir
        )
        autopatcher.insert_partition_info(
            os.path.join(tempdir, 'init.multiboot.mounting.sh'),
            self.file_info.partconfig, target_path_only=True
        )
        cf.add_file(
            os.path.join(tempdir, 'init.multiboot.mounting.sh'),
            name='init.multiboot.mounting.sh',
            perms=0o750
        )
        os.remove(os.path.join(tempdir, 'init.multiboot.mounting.sh'))

        # Copy busybox
        cf.add_file(
            os.path.join(OS.ramdiskdir, 'busybox-static'),
            name='sbin/busybox-static',
            perms=0o750
        )

        # Copy syncdaemon
        cf.add_file(
            os.path.join(OS.ramdiskdir, 'syncdaemon'),
            name='sbin/syncdaemon',
            perms=0o750
        )

        # Copy patched init if needed
        if self.file_info.patchinfo.patched_init is not None:
            cf.add_file(
                os.path.join(OS.ramdiskdir, 'init',
                             self.file_info.patchinfo.patched_init),
                name='init',
                perms=0o755
            )

        # Create gzip compressed ramdisk
        OS.ui.details('Creating gzip compressed ramdisk with minicpio ...')

        target_ramdisk = target_ramdisk + ".gz"

        with gzip.open(target_ramdisk, 'wb') as f_out:
            data = cf.create()

            if data is not None:
                f_out.write(data)
            else:
                OS.ui.failed('Failed to create gzip compressed ramdisk')
                return None

        OS.ui.details('Running mkbootimg ...')

        bootimageinfo.kernel = target_kernel
        bootimageinfo.ramdisk = target_ramdisk

        new_boot_image = tempfile.mkstemp()

        try:
            bootimage.create(bootimageinfo, new_boot_image[1])
        except bootimage.CreateError as e:
            OS.ui.failed('Failed to create boot image: ' + str(e))
            os.close(new_boot_image[0])
            os.remove(new_boot_image[1])
            return None

        os.remove(target_kernel)
        os.remove(target_ramdisk)

        os.close(new_boot_image[0])
        return new_boot_image[1]