Exemple #1
0
void EnableArchiveFormats(struct archive *p_archive)
{
    //    archive_read_support_filter_bzip2(p_archive);
    //    archive_read_support_filter_compress(p_archive);
    //    archive_read_support_filter_gzip(p_archive);
    //    archive_read_support_filter_grzip(p_archive);
    //    archive_read_support_filter_lrzip(p_archive);
    //    archive_read_support_filter_lzip(p_archive);
    archive_read_support_filter_lzma(p_archive);
    archive_read_support_filter_lzop(p_archive);
    archive_read_support_filter_none(p_archive);
    archive_read_support_filter_rpm(p_archive);
    archive_read_support_filter_uu(p_archive);
    archive_read_support_filter_xz(p_archive);

    //    archive_read_support_format_7zip(p_archive);
    archive_read_support_format_ar(p_archive);
    archive_read_support_format_cab(p_archive);
    archive_read_support_format_cpio(p_archive);
    archive_read_support_format_gnutar(p_archive);
    //    archive_read_support_format_iso9660(p_archive);
    archive_read_support_format_lha(p_archive);
    archive_read_support_format_mtree(p_archive);
    archive_read_support_format_rar(p_archive);
    archive_read_support_format_raw(p_archive);
    archive_read_support_format_tar(p_archive);
    archive_read_support_format_xar(p_archive);
    //    archive_read_support_format_zip(p_archive);
}
int
archive_read_support_filter_all(struct archive *a)
{
	archive_check_magic(a, ARCHIVE_READ_MAGIC,
	    ARCHIVE_STATE_NEW, "archive_read_support_filter_all");

	/* Bzip falls back to "bunzip2" command-line */
	archive_read_support_filter_bzip2(a);
	/* The decompress code doesn't use an outside library. */
	archive_read_support_filter_compress(a);
	/* Gzip decompress falls back to "gzip -d" command-line. */
	archive_read_support_filter_gzip(a);
	/* Lzip falls back to "unlzip" command-line program. */
	archive_read_support_filter_lzip(a);
	/* The LZMA file format has a very weak signature, so it
	 * may not be feasible to keep this here, but we'll try.
	 * This will come back out if there are problems. */
	/* Lzma falls back to "unlzma" command-line program. */
	archive_read_support_filter_lzma(a);
	/* Xz falls back to "unxz" command-line program. */
	archive_read_support_filter_xz(a);
	/* The decode code doesn't use an outside library. */
	archive_read_support_filter_uu(a);
	/* The decode code doesn't use an outside library. */
	archive_read_support_filter_rpm(a);
	/* The decode code always uses "lrzip -q -d" command-line. */
	archive_read_support_filter_lrzip(a);
	/* Lzop decompress falls back to "lzop -d" command-line. */
	archive_read_support_filter_lzop(a);
	/* The decode code always uses "grzip -d" command-line. */
	archive_read_support_filter_grzip(a);
	/* Lz4 falls back to "lz4 -d" command-line program. */
	archive_read_support_filter_lz4(a);
	/* Zstd falls back to "zstd -d" command-line program. */
	archive_read_support_filter_zstd(a);

	/* Note: We always return ARCHIVE_OK here, even if some of the
	 * above return ARCHIVE_WARN.  The intent here is to enable
	 * "as much as possible."  Clients who need specific
	 * compression should enable those individually so they can
	 * verify the level of support. */
	/* Clear any warning messages set by the above functions. */
	archive_clear_error(a);
	return (ARCHIVE_OK);
}
Installer::ProceedState RomInstaller::on_checked_device()
{
    // /sbin is not going to be populated with anything useful in a normal boot
    // image. We can almost guarantee that a recovery image is going to be
    // installed though, so we'll open the recovery partition with libmbp and
    // extract its /sbin with libarchive into the chroot's /sbin.

    std::string block_dev(_recovery_block_dev);
    mbp::BootImage bi;
    mbp::CpioFile innerCpio;
    const unsigned char *ramdisk_data;
    std::size_t ramdisk_size;
    bool using_boot = false;

    // Check if the device has a combined boot/recovery partition. If the
    // FOTAKernel partition is listed, it will be used instead of the combined
    // ramdisk from the boot image
    bool combined = mb_device_flags(_device)
            & FLAG_HAS_COMBINED_BOOT_AND_RECOVERY;
    if (combined && block_dev.empty()) {
        block_dev = _boot_block_dev;
        using_boot = true;
    }

    if (block_dev.empty()) {
        display_msg("Could not determine the recovery block device");
        return ProceedState::Fail;
    }

    if (!bi.loadFile(block_dev)) {
        display_msg("Failed to load recovery partition image");
        return ProceedState::Fail;
    }

    // Load ramdisk
    bi.ramdiskImageC(&ramdisk_data, &ramdisk_size);

    if (using_boot) {
        if (!innerCpio.load(ramdisk_data, ramdisk_size)) {
            display_msg("Failed to load ramdisk from combined boot image");
            return ProceedState::Fail;
        }

        if (!innerCpio.contentsC("sbin/ramdisk-recovery.cpio",
                                 &ramdisk_data, &ramdisk_size)) {
            display_msg("Could not find recovery ramdisk in combined boot image");
            return ProceedState::Fail;
        }
    }

    autoclose::archive in(archive_read_new(), archive_read_free);
    autoclose::archive out(archive_write_disk_new(), archive_write_free);

    if (!in || !out) {
        LOGE("Out of memory");
        return ProceedState::Fail;
    }

    archive_entry *entry;

    // Set up input
    archive_read_support_filter_gzip(in.get());
    archive_read_support_filter_lzop(in.get());
    archive_read_support_filter_lz4(in.get());
    archive_read_support_filter_lzma(in.get());
    archive_read_support_filter_xz(in.get());
    archive_read_support_format_cpio(in.get());

    int ret = archive_read_open_memory(in.get(),
            const_cast<unsigned char *>(ramdisk_data), ramdisk_size);
    if (ret != ARCHIVE_OK) {
        LOGW("Failed to open recovery ramdisk: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    // Set up output
    archive_write_disk_set_options(out.get(),
                                   ARCHIVE_EXTRACT_ACL |
                                   ARCHIVE_EXTRACT_FFLAGS |
                                   ARCHIVE_EXTRACT_PERM |
                                   ARCHIVE_EXTRACT_SECURE_NODOTDOT |
                                   ARCHIVE_EXTRACT_SECURE_SYMLINKS |
                                   ARCHIVE_EXTRACT_TIME |
                                   ARCHIVE_EXTRACT_UNLINK |
                                   ARCHIVE_EXTRACT_XATTR);

    while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) {
        std::string path = archive_entry_pathname(entry);

        if (path == "default.prop") {
            path = "default.recovery.prop";
        } else if (!util::starts_with(path, "sbin/")) {
            continue;
        }

        LOGE("Copying from recovery: %s", path.c_str());

        archive_entry_set_pathname(entry, in_chroot(path).c_str());

        if (util::libarchive_copy_header_and_data(
                in.get(), out.get(), entry) != ARCHIVE_OK) {
            return ProceedState::Fail;
        }

        archive_entry_set_pathname(entry, path.c_str());
    }

    if (ret != ARCHIVE_EOF) {
        LOGE("Archive extraction ended without reaching EOF: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    // Create fake /etc/fstab file to please installers that read the file
    std::string etc_fstab(in_chroot("/etc/fstab"));
    if (access(etc_fstab.c_str(), R_OK) < 0 && errno == ENOENT) {
        autoclose::file fp(autoclose::fopen(etc_fstab.c_str(), "w"));
        if (fp) {
            auto system_devs = mb_device_system_block_devs(_device);
            auto cache_devs = mb_device_cache_block_devs(_device);
            auto data_devs = mb_device_data_block_devs(_device);

            // Set block device if it's provided and non-empty
            const char *system_dev =
                    system_devs && system_devs[0] && system_devs[0][0]
                    ? system_devs[0] : "dummy";
            const char *cache_dev =
                    cache_devs && cache_devs[0] && cache_devs[0][0]
                    ? cache_devs[0] : "dummy";
            const char *data_dev =
                    data_devs && data_devs[0] && data_devs[0][0]
                    ? data_devs[0] : "dummy";

            fprintf(fp.get(), "%s /system ext4 rw 0 0\n", system_dev);
            fprintf(fp.get(), "%s /cache ext4 rw 0 0\n", cache_dev);
            fprintf(fp.get(), "%s /data ext4 rw 0 0\n", data_dev);
        }
    }

    // Load recovery properties
    util::file_get_all_properties(
            in_chroot("/default.recovery.prop"), &_recovery_props);

    return ProceedState::Continue;
}
Installer::ProceedState RomInstaller::on_checked_device()
{
    // /sbin is not going to be populated with anything useful in a normal boot
    // image. We can almost guarantee that a recovery image is going to be
    // installed though, so we'll open the recovery partition with libmbp and
    // extract its /sbin with libarchive into the chroot's /sbin.

    mbp::BootImage bi;
    if (!bi.loadFile(_recovery_block_dev)) {
        display_msg("Failed to load recovery partition image");
        return ProceedState::Fail;
    }

    const unsigned char *ramdisk_data;
    std::size_t ramdisk_size;
    bi.ramdiskImageC(&ramdisk_data, &ramdisk_size);

    autoclose::archive in(archive_read_new(), archive_read_free);
    autoclose::archive out(archive_write_disk_new(), archive_write_free);

    if (!in | !out) {
        LOGE("Out of memory");
        return ProceedState::Fail;
    }

    archive_entry *entry;

    // Set up input
    archive_read_support_filter_gzip(in.get());
    archive_read_support_filter_lzop(in.get());
    archive_read_support_filter_lz4(in.get());
    archive_read_support_filter_lzma(in.get());
    archive_read_support_format_cpio(in.get());

    int ret = archive_read_open_memory(in.get(),
            const_cast<unsigned char *>(ramdisk_data), ramdisk_size);
    if (ret != ARCHIVE_OK) {
        LOGW("Failed to open recovery ramdisk: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    // Set up output
    archive_write_disk_set_options(out.get(),
                                   ARCHIVE_EXTRACT_ACL |
                                   ARCHIVE_EXTRACT_FFLAGS |
                                   ARCHIVE_EXTRACT_PERM |
                                   ARCHIVE_EXTRACT_SECURE_NODOTDOT |
                                   ARCHIVE_EXTRACT_SECURE_SYMLINKS |
                                   ARCHIVE_EXTRACT_TIME |
                                   ARCHIVE_EXTRACT_UNLINK |
                                   ARCHIVE_EXTRACT_XATTR);

    while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) {
        std::string path = archive_entry_pathname(entry);

        if (!util::starts_with(path, "sbin/")) {
            continue;
        }

        LOGE("Copying from recovery: %s", path.c_str());

        archive_entry_set_pathname(entry, (_chroot + "/" + path).c_str());

        if (util::archive_copy_header_and_data(in.get(), out.get(), entry) != ARCHIVE_OK) {
            return ProceedState::Fail;
        }

        archive_entry_set_pathname(entry, path.c_str());
    }

    if (ret != ARCHIVE_EOF) {
        LOGE("Archive extraction ended without reaching EOF: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    return ProceedState::Continue;
}
Exemple #5
0
/**
 * Extract the archive stored at the given @path.  This function
 * returns -1 if an error occurred, otherwise 0.
 */
int extract_archive_from_file(const char *path)
{
    struct archive *archive = NULL;
    CallbackData *data = NULL;
    int status2;
    int status;

    archive = archive_read_new();
    if (archive == NULL) {
        note(NULL, ERROR, INTERNAL, "can't initialize archive structure");
        status = -1;
        goto end;
    }

    status = archive_read_support_format_cpio(archive);
    if (status != ARCHIVE_OK) {
        note(NULL, ERROR, INTERNAL, "can't set archive format: %s",
             archive_error_string(archive));
        status = -1;
        goto end;
    }

    status = archive_read_support_format_gnutar(archive);
    if (status != ARCHIVE_OK) {
        note(NULL, ERROR, INTERNAL, "can't set archive format: %s",
             archive_error_string(archive));
        status = -1;
        goto end;
    }

    status = archive_read_support_filter_gzip(archive);
    if (status != ARCHIVE_OK) {
        note(NULL, ERROR, INTERNAL, "can't add archive filter: %s",
             archive_error_string(archive));
        status = -1;
        goto end;
    }

    status = archive_read_support_filter_lzop(archive);
    if (status != ARCHIVE_OK) {
        note(NULL, ERROR, INTERNAL, "can't add archive filter: %s",
             archive_error_string(archive));
        status = -1;
        goto end;
    }

    data = talloc_zero(NULL, CallbackData);
    if (data == NULL) {
        note(NULL, ERROR, INTERNAL, "can't allocate callback data");
        status = -1;
        goto end;

    }

    data->path = talloc_strdup(data, path);
    if (data->path == NULL) {
        note(NULL, ERROR, INTERNAL, "can't allocate callback data path");
        status = -1;
        goto end;

    }

    status = archive_read_open(archive, data, open_callback, read_callback, close_callback);
    if (status != ARCHIVE_OK) {
        /* Don't complain if no error message were registered,
         * ie. when testing for a self-extracting archive.  */
        if (archive_error_string(archive) != NULL)
            note(NULL, ERROR, INTERNAL, "can't read archive: %s",
                 archive_error_string(archive));
        status = -1;
        goto end;
    }

    status = extract_archive(archive);
end:
    if (archive != NULL) {
        status2 = archive_read_close(archive);
        if (status2 != ARCHIVE_OK) {
            note(NULL, WARNING, INTERNAL, "can't close archive: %s",
                 archive_error_string(archive));
        }

        status2 = archive_read_free(archive);
        if (status2 != ARCHIVE_OK) {
            note(NULL, WARNING, INTERNAL, "can't free archive: %s",
                 archive_error_string(archive));
        }
    }

    TALLOC_FREE(data);

    return status;
}