struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src, int flags) { struct mp_archive *mpa = talloc_zero(NULL, struct mp_archive); mpa->log = log; mpa->locale = newlocale(LC_ALL_MASK, "C.UTF-8", (locale_t)0); if (!mpa->locale) goto err; mpa->arch = archive_read_new(); mpa->primary_src = src; if (!mpa->arch) goto err; // first volume is the primary streame if (!add_volume(log ,mpa, src, src->url)) goto err; // try to open other volumes char** volumes = find_volumes(src); for (int i = 0; volumes[i]; i++) { if (!add_volume(log, mpa, NULL, volumes[i])) { talloc_free(volumes); goto err; } } talloc_free(volumes); locale_t oldlocale = uselocale(mpa->locale); archive_read_support_format_7zip(mpa->arch); archive_read_support_format_iso9660(mpa->arch); archive_read_support_format_rar(mpa->arch); archive_read_support_format_zip(mpa->arch); archive_read_support_filter_bzip2(mpa->arch); archive_read_support_filter_gzip(mpa->arch); archive_read_support_filter_xz(mpa->arch); if (flags & MP_ARCHIVE_FLAG_UNSAFE) { archive_read_support_format_gnutar(mpa->arch); archive_read_support_format_tar(mpa->arch); } archive_read_set_read_callback(mpa->arch, read_cb); archive_read_set_skip_callback(mpa->arch, skip_cb); archive_read_set_switch_callback(mpa->arch, switch_cb); archive_read_set_open_callback(mpa->arch, open_cb); archive_read_set_close_callback(mpa->arch, close_cb); if (mpa->primary_src->seekable) archive_read_set_seek_callback(mpa->arch, seek_cb); bool fail = archive_read_open1(mpa->arch) < ARCHIVE_OK; uselocale(oldlocale); if (fail) goto err; return mpa; err: mp_archive_free(mpa); return NULL; }
bool OdinPatcher::Impl::openInputArchive() { assert(aInput == nullptr); aInput = archive_read_new(); // TODO: Eventually support tar within a zip since many people distribute // stock firmware packages in this format //archive_read_support_format_zip(aInput); archive_read_support_format_tar(aInput); archive_read_support_filter_gzip(aInput); archive_read_support_filter_xz(aInput); // Our callbacks use io::File, which supports LFS on Android. Also allows // progress info by counting number of bytes read. int ret = archive_read_open2(aInput, this, &Impl::laOpenCb, &Impl::laReadCb, &Impl::laSkipCb, &Impl::laCloseCb); if (ret != ARCHIVE_OK) { LOGW("libarchive: Failed to open for reading: %s", archive_error_string(aInput)); archive_read_free(aInput); aInput = nullptr; error = ErrorCode::ArchiveReadOpenError; return false; } return true; }
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 "gunzip" 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); /* 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); }
static void extract (int fd) { struct archive *a; struct archive *ext; struct archive_entry *entry; int r; a = archive_read_new (); ext = archive_write_disk_new (); archive_read_support_format_tar (a); archive_read_support_filter_xz (a); archive_read_support_filter_gzip (a); if ((r = archive_read_open_fd (a, fd, 16*1024))) die_with_libarchive (a, "archive_read_open_fd: %s"); while (1) { r = archive_read_next_header (a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) die_with_libarchive (a, "archive_read_next_header: %s"); if (!should_extract (entry)) continue; r = archive_write_header (ext, entry); if (r != ARCHIVE_OK) die_with_libarchive (ext, "archive_write_header: %s"); else { copy_archive (a, ext); r = archive_write_finish_entry (ext); if (r != ARCHIVE_OK) die_with_libarchive (ext, "archive_write_finish_entry: %s"); } } archive_read_close (a); archive_read_free (a); archive_write_close (ext); archive_write_free (ext); }
/* * All of the sample files have the same contents; they're just * compressed in different ways. */ static void compat_xz(const char *name) { const char *n[7] = { "f1", "f2", "f3", "d1/f1", "d1/f2", "d1/f3", NULL }; struct archive_entry *ae; struct archive *a; int i, r; assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); r = archive_read_support_filter_xz(a); if (r == ARCHIVE_WARN) { skipping("xz reading not fully supported on this platform"); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); return; } assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); extract_reference_file(name); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 2)); /* Read entries, match up names with list above. */ for (i = 0; i < 6; ++i) { failure("Could not read file %d (%s) from %s", i, n[i], name); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString(n[i], archive_entry_pathname(ae)); } /* Verify the end-of-archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify that the format detection worked. */ assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_XZ); assertEqualString(archive_filter_name(a, 0), "xz"); assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR); assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
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; }
int archive_read_append_filter(struct archive *_a, int code) { int r1, r2, number_bidders, i; char str[20]; struct archive_read_filter_bidder *bidder; struct archive_read_filter *filter; struct archive_read *a = (struct archive_read *)_a; r1 = r2 = (ARCHIVE_OK); switch (code) { case ARCHIVE_FILTER_NONE: /* No filter to add, so do nothing. * NOTE: An initial "NONE" type filter is always set at the end of the * filter chain. */ r1 = (ARCHIVE_OK); break; case ARCHIVE_FILTER_GZIP: strcpy(str, "gzip"); r1 = archive_read_support_filter_gzip(_a); break; case ARCHIVE_FILTER_BZIP2: strcpy(str, "bzip2"); r1 = archive_read_support_filter_bzip2(_a); break; case ARCHIVE_FILTER_COMPRESS: strcpy(str, "compress (.Z)"); r1 = archive_read_support_filter_compress(_a); break; case ARCHIVE_FILTER_PROGRAM: archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Cannot append program filter using archive_read_append_filter"); return (ARCHIVE_FATAL); case ARCHIVE_FILTER_LZMA: strcpy(str, "lzma"); r1 = archive_read_support_filter_lzma(_a); break; case ARCHIVE_FILTER_XZ: strcpy(str, "xz"); r1 = archive_read_support_filter_xz(_a); break; case ARCHIVE_FILTER_UU: strcpy(str, "uu"); r1 = archive_read_support_filter_uu(_a); break; case ARCHIVE_FILTER_RPM: strcpy(str, "rpm"); r1 = archive_read_support_filter_rpm(_a); break; case ARCHIVE_FILTER_LZIP: strcpy(str, "lzip"); r1 = archive_read_support_filter_lzip(_a); break; case ARCHIVE_FILTER_LRZIP: strcpy(str, "lrzip"); r1 = archive_read_support_filter_lrzip(_a); break; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Invalid filter code specified"); return (ARCHIVE_FATAL); } if (code != ARCHIVE_FILTER_NONE) { number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); bidder = a->bidders; for (i = 0; i < number_bidders; i++, bidder++) { if (!bidder->name || !strcmp(bidder->name, str)) break; } if (!bidder->name || strcmp(bidder->name, str)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: Unable to append filter"); return (ARCHIVE_FATAL); } filter = (struct archive_read_filter *)calloc(1, sizeof(*filter)); if (filter == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } filter->bidder = bidder; filter->archive = a; filter->upstream = a->filter; a->filter = filter; r2 = (bidder->init)(a->filter); if (r2 != ARCHIVE_OK) { __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } } a->bypass_filter_bidding = 1; return (r1 < r2) ? r1 : r2; }
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_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; } // Load recovery properties util::file_get_all_properties( in_chroot("/default.recovery.prop"), &_recovery_props); return ProceedState::Continue; }
bool extract_archive(const char *filename, const char *target) { struct archive *in = NULL; struct archive *out = NULL; struct archive_entry *entry; int ret; char *cwd = NULL; if (!(in = archive_read_new())) { LOGE("Out of memory"); goto error; } // Add more as needed //archive_read_support_format_all(in); //archive_read_support_filter_all(in); archive_read_support_format_tar(in); archive_read_support_format_zip(in); archive_read_support_filter_xz(in); if (archive_read_open_filename(in, filename, 10240) != ARCHIVE_OK) { LOGE("%s: Failed to open archive: %s", filename, archive_error_string(in)); goto error; } if (!(out = archive_write_disk_new())) { LOGE("Out of memory"); goto error; } archive_write_disk_set_options(out, 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); if (!(cwd = getcwd(NULL, 0))) { LOGE("Failed to get cwd: %s", strerror(errno)); goto error; } if (chdir(target) < 0) { LOGE("%s: Failed to change to target directory: %s", target, strerror(errno)); goto error; } while ((ret = archive_read_next_header(in, &entry)) == ARCHIVE_OK) { if ((ret = archive_write_header(out, entry)) != ARCHIVE_OK) { LOGE("Failed to write header: %s", archive_error_string(out)); goto error; } const void *buff; size_t size; int64_t offset; int ret; while ((ret = archive_read_data_block( in, &buff, &size, &offset)) == ARCHIVE_OK) { if (archive_write_data_block(out, buff, size, offset) != ARCHIVE_OK) { LOGE("Failed to write data: %s", archive_error_string(out)); goto error; } } if (ret != ARCHIVE_EOF) { LOGE("Data copy ended without reaching EOF: %s", archive_error_string(in)); goto error; } } if (ret != ARCHIVE_EOF) { LOGE("Archive extraction ended without reaching EOF: %s", archive_error_string(in)); goto error; } chdir(cwd); archive_read_free(in); archive_write_free(out); return true; error: if (cwd) { chdir(cwd); } archive_read_free(in); archive_write_free(out); return false; }