static void extract(const char *filename, int do_extract, int flags) { struct archive *a; struct archive *ext; struct archive_entry *entry; int r; a = archive_read_new(); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); /* * Note: archive_write_disk_set_standard_lookup() is useful * here, but it requires library routines that can add 500k or * more to a static executable. */ archive_read_support_format_tar(a); /* * On my system, enabling other archive formats adds 20k-30k * each. Enabling gzip decompression adds about 20k. * Enabling bzip2 is more expensive because the libbz2 library * isn't very well factored. */ if (filename != NULL && strcmp(filename, "-") == 0) filename = NULL; if ((r = archive_read_open_filename(a, filename, 10240))) fail("archive_read_open_filename()", archive_error_string(a), r); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) fail("archive_read_next_header()", archive_error_string(a), 1); if (verbose && do_extract) msg("x "); if (verbose || !do_extract) msg(archive_entry_pathname(entry)); if (do_extract) { r = archive_write_header(ext, entry); if (r != ARCHIVE_OK) warn("archive_write_header()", archive_error_string(ext)); else { copy_data(a, ext); r = archive_write_finish_entry(ext); if (r != ARCHIVE_OK) fail("archive_write_finish_entry()", archive_error_string(ext), 1); } } if (verbose || !do_extract) msg("\n"); } archive_read_close(a); archive_read_free(a); exit(0); }
int Tarball::install () { archive_entry *entry; int r; archive* a = archive_read_new(); archive_read_support_format_all(a); archive_read_support_filter_all(a); archive* ext = archive_write_disk_new(); const int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS; archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); const std::string subdir = "deps"; const std::string filename = subdir + "/" + basename(this->location); printf("Unpacking archive %s\n", filename.c_str()); if ((r = archive_read_open_filename(a,filename.c_str(), 10240))) { fprintf(stderr, "Error opening archive:\n%s\n", archive_error_string(a)); return -1; } for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) { break; } if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(a)); } if (r < ARCHIVE_WARN) { return -1; } rewrite_subdir(entry, subdir); r = archive_write_header(ext, entry); if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(ext)); } else if (archive_entry_size(entry) > 0) { r = copy_data(a, ext); if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(ext)); } if (r < ARCHIVE_WARN) { return -1; } } r = archive_write_finish_entry(ext); if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(ext)); } if (r < ARCHIVE_WARN) { return -1; } } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); return 0; };
int packing_init(struct packing **pack, const char *path, pkg_formats format) { char archive_path[MAXPATHLEN]; const char *ext; assert(pack != NULL); if ((*pack = calloc(1, sizeof(struct packing))) == NULL) { pkg_emit_errno("calloc", "packing"); return (EPKG_FATAL); } (*pack)->aread = archive_read_disk_new(); archive_read_disk_set_standard_lookup((*pack)->aread); archive_read_disk_set_symlink_physical((*pack)->aread); if (!is_dir(path)) { (*pack)->pass = false; (*pack)->awrite = archive_write_new(); archive_write_set_format_pax_restricted((*pack)->awrite); ext = packing_set_format((*pack)->awrite, format); if (ext == NULL) { archive_read_close((*pack)->aread); archive_read_free((*pack)->aread); archive_write_close((*pack)->awrite); archive_write_free((*pack)->awrite); *pack = NULL; return EPKG_FATAL; /* error set by _set_format() */ } snprintf(archive_path, sizeof(archive_path), "%s.%s", path, ext); pkg_debug(1, "Packing to file '%s'", archive_path); if (archive_write_open_filename( (*pack)->awrite, archive_path) != ARCHIVE_OK) { pkg_emit_errno("archive_write_open_filename", archive_path); archive_read_close((*pack)->aread); archive_read_free((*pack)->aread); archive_write_close((*pack)->awrite); archive_write_free((*pack)->awrite); *pack = NULL; return EPKG_FATAL; } } else { /* pass mode directly write to the disk */ pkg_debug(1, "Packing to directory '%s' (pass mode)", path); (*pack)->pass = true; (*pack)->awrite = archive_write_disk_new(); archive_write_disk_set_options((*pack)->awrite, EXTRACT_ARCHIVE_FLAGS); } (*pack)->resolver = archive_entry_linkresolver_new(); archive_entry_linkresolver_set_strategy((*pack)->resolver, ARCHIVE_FORMAT_TAR_PAX_RESTRICTED); return (EPKG_OK); }
/* * memory to file */ int archive_extract_file3( void *arch_buff, size_t arch_size, const char *src, char *dest ) { int flags; const char *filename; struct archive *arch_r = NULL, *arch_w = NULL; struct archive_entry *entry; if( !src || !dest ) return -1; arch_r = archive_read_new(); archive_read_support_format_all( arch_r ); archive_read_support_compression_all( arch_r ); if( archive_read_open_memory( arch_r, arch_buff, arch_size ) != ARCHIVE_OK ) goto errout; while( archive_read_next_header( arch_r, &entry ) == ARCHIVE_OK ) { filename = archive_entry_pathname( entry ); if( fnmatch( src, filename, FNM_PATHNAME | FNM_PERIOD ) ) { if( archive_read_data_skip( arch_r ) != ARCHIVE_OK ) { goto errout; } } else { #ifdef DEBUG printf("extract:%s\n", filename ); #endif flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS; arch_w = archive_write_disk_new(); archive_write_disk_set_options( arch_w, flags ); archive_write_disk_set_standard_lookup( arch_w ); archive_entry_set_pathname( entry, dest ); if( archive_read_extract2( arch_r, entry, arch_w ) != ARCHIVE_OK ) goto errout; archive_write_finish( arch_w ); } } archive_read_finish( arch_r ); return 0; errout: #ifdef DEBUG fprintf( stderr, "%s\n", archive_error_string( arch_r ) ); #endif if( arch_r ) archive_read_finish( arch_r ); if( arch_w ) archive_write_finish( arch_w ); return -1; }
int extract_archive(const char* filename, const char* to_path) { struct archive* a; struct archive* ext; struct archive_entry* entry; int r; int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS; a = archive_read_new(); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); archive_read_support_format_all(a); archive_read_support_compression_all(a); if(filename != NULL && strcmp(filename, "-") == 0) { filename = NULL; } if((r = archive_read_open_file(a, filename, 10240))) { printf("archive_read_open_file(): %s\n", archive_error_string(a)); return r; } for(;;) { r = archive_read_next_header(a, &entry); if(r == ARCHIVE_EOF) { break; } if(r != ARCHIVE_OK) { printf("archive_read_next_header(): %s\n", archive_error_string(a)); return 0; } // rewrite pathname const char* path = archive_entry_pathname(entry); char new_path[PATH_MAX + 1]; sprintf(new_path, "%s/%s", to_path, path + (strncmp(path, "rootfs/", 7) == 0 ? 7 : 0)); archive_entry_set_pathname(entry, new_path); r = archive_write_header(ext, entry); if(r != ARCHIVE_OK) { printf("archive_write_header(): %s\n", archive_error_string(ext)); } else { copy_data(a, ext); if(r != ARCHIVE_OK) { printf("archive_write_finish_entry(): %s\n", archive_error_string(ext)); return 0; } } r = archive_write_finish_entry(ext); } archive_read_close(a); archive_read_finish(a); archive_write_close(ext); archive_write_finish(ext); return 1; }
static void extract_recovery(char *ramdisk_path) { // Delete everything in the current root DIR *root = opendir("/"); struct dirent *dp; while ((dp = readdir(root)) != NULL) { unlink(dp->d_name); } closedir(root); // Open the ramdisk struct archive *a = archive_read_new(); archive_read_support_filter_lzma(a); archive_read_support_format_cpio(a); if (archive_read_open_filename(a, ramdisk_path, 4096) == ARCHIVE_OK) { // Set up the writer struct archive *ext = archive_write_disk_new(); archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_UNLINK | ARCHIVE_EXTRACT_PERM); chdir("/"); while (1) { struct archive_entry *entry; // Read the next file if (archive_read_next_header(a, &entry) == ARCHIVE_EOF) break; // Create the file archive_write_header(ext, entry); // If the file has data to write... if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) { const void *block; size_t size; int64_t offset; // Write the blocks until EOF while (1) { if (archive_read_data_block(a, &block, &size, &offset) == ARCHIVE_EOF) break; archive_write_data_block(ext, block, size, offset); } } } archive_write_free(ext); } archive_read_free(a); }
int archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags) { struct extract *extract; extract = get_extract((struct archive_read *)_a); if (extract == NULL) return (ARCHIVE_FATAL); archive_write_disk_set_options(extract->ad, flags); return (archive_read_extract2(_a, entry, extract->ad)); }
static void mode_pass(struct cpio *cpio, const char *destdir) { struct lafe_line_reader *lr; const char *p; int r; /* Ensure target dir has a trailing '/' to simplify path surgery. */ cpio->destdir = malloc(strlen(destdir) + 8); strcpy(cpio->destdir, destdir); if (destdir[strlen(destdir) - 1] != '/') strcat(cpio->destdir, "/"); cpio->archive = archive_write_disk_new(); if (cpio->archive == NULL) lafe_errc(1, 0, "Failed to allocate archive object"); r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); cpio->linkresolver = archive_entry_linkresolver_new(); archive_write_disk_set_standard_lookup(cpio->archive); cpio->archive_read_disk = archive_read_disk_new(); if (cpio->archive_read_disk == NULL) lafe_errc(1, 0, "Failed to allocate archive object"); if (cpio->option_follow_links) archive_read_disk_set_symlink_logical(cpio->archive_read_disk); else archive_read_disk_set_symlink_physical(cpio->archive_read_disk); archive_read_disk_set_standard_lookup(cpio->archive_read_disk); lr = lafe_line_reader("-", cpio->option_null); while ((p = lafe_line_reader_next(lr)) != NULL) file_to_archive(cpio, p); lafe_line_reader_free(lr); archive_entry_linkresolver_free(cpio->linkresolver); r = archive_write_close(cpio->archive); if (cpio->dot) fprintf(stderr, "\n"); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); if (!cpio->quiet) { int64_t blocks = (archive_filter_bytes(cpio->archive, 0) + 511) / 512; fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } archive_write_free(cpio->archive); }
static void set_up_output(archive *out) { 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); }
// Based on libarchive's public example code. // https://github.com/libarchive/libarchive/wiki/Examples#wiki-Constructing_Objects_On_Disk void GuiZipper::unpackFile(const char *zipFile, const char *outputDir) throw (ZipperException*) { // TODO: use archive_write_disk_open instead (if/when it exists) char cwd[4096]; getcwd(cwd, 4096); char *absZipFile = fileManager_->getAbsFilePath(zipFile); platformstl::filesystem_traits<char> traits; traits.set_current_directory(outputDir); struct archive *a; struct archive *ext; struct archive_entry *entry; int flags; int r; flags = ARCHIVE_EXTRACT_TIME; flags |= ARCHIVE_EXTRACT_PERM; flags |= ARCHIVE_EXTRACT_ACL; flags |= ARCHIVE_EXTRACT_FFLAGS; a = archive_read_new(); archive_read_support_format_tar(a); archive_read_support_filter_gzip(a); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); r = archive_read_open_filename(a, absZipFile, 10240); checkForErrors("Error opening archive for reading", a, r); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) { break; } checkForErrors("Error reading next archive header", a, r); r = archive_write_header(ext, entry); checkForErrors("Error writing next archive header", a, r); copyData(a, ext, outputDir); r = archive_write_finish_entry(ext); checkForErrors("Error writing archive finish entry", a, r); } r = archive_read_close(a); checkForErrors("Error closing read archive", a, r); r = archive_read_free(a); checkForErrors("Error freeing read archive", a, r); r = archive_write_close(ext); checkForErrors("Error closing write archive", a, r); r = archive_write_free(ext); checkForErrors("Error freeing write archive", a, r); traits.set_current_directory(cwd); delete absZipFile; }
static void extract(const char *filename) { struct archive *a; struct archive *ext; struct archive_entry *entry; int flags; int r; flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM; a = archive_read_new(); archive_read_support_format_all(a); #if ARCHIVE_VERSION_NUMBER < 3000000 archive_read_support_compression_all(a); #else archive_read_support_filter_all(a); #endif ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); #if ARCHIVE_VERSION_NUMBER < 3000000 if ((r = archive_read_open_file(a, filename, 10240))) die("archive_read_open_file"); #else if ((r = archive_read_open_filename(a, filename, 10240))) die("archive_read_open_filename"); #endif for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_WARN) die(archive_error_string(a)); r = archive_write_header(ext, entry); if (r == ARCHIVE_OK && archive_entry_size(entry) > 0) { r = copy_data(a, ext); if (r < ARCHIVE_WARN) die(archive_error_string(a)); } r = archive_write_finish_entry(ext); if (r < ARCHIVE_WARN) die(archive_error_string(ext)); } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); }
void tar_mode_x(struct bsdtar *bsdtar) { struct archive *writer; writer = archive_write_disk_new(); if (writer == NULL) lafe_errc(1, ENOMEM, "Cannot allocate disk writer object"); if (!bsdtar->option_numeric_owner) archive_write_disk_set_standard_lookup(writer); archive_write_disk_set_options(writer, bsdtar->extract_flags); read_archive(bsdtar, 'x', writer); if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0) bsdtar->return_value = 1; archive_write_free(writer); }
static void create_reg_file(struct archive_entry *ae, const char *msg) { static const char data[]="abcdefghijklmnopqrstuvwxyz"; struct archive *ad; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME); failure("%s", msg); /* * A touchy API design issue: archive_write_data() does (as of * 2.4.12) enforce the entry size as a limit on the data * written to the file. This was not enforced prior to * 2.4.12. The change was prompted by the refined * hardlink-restore semantics introduced at that time. In * short, libarchive needs to know whether a "hardlink entry" * is going to overwrite the contents so that it can know * whether or not to open the file for writing. This implies * that there is a fundamental semantic difference between an * entry with a zero size and one with a non-zero size in the * case of hardlinks and treating the hardlink case * differently from the regular file case is just asking for * trouble. So, a zero size must always mean that no data * will be accepted, which is consistent with the file size in * the entry being a maximum size. */ archive_entry_set_size(ae, sizeof(data)); archive_entry_set_mtime(ae, 123456789, 0); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data))); assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); #if ARCHIVE_VERSION_NUMBER < 2000000 archive_write_finish(ad); #else assertEqualInt(0, archive_write_finish(ad)); #endif /* Test the entries on disk. */ assertIsReg(archive_entry_pathname(ae), archive_entry_mode(ae) & 0777); assertFileSize(archive_entry_pathname(ae), sizeof(data)); /* test_write_disk_times has more detailed tests of this area. */ assertFileMtime(archive_entry_pathname(ae), 123456789, 0); failure("No atime given, so atime should get set to current time"); assertFileAtimeRecent(archive_entry_pathname(ae)); }
static void mode_pass(struct cpio *cpio, const char *destdir) { unsigned long blocks; struct line_reader *lr; const char *p; int r; /* Ensure target dir has a trailing '/' to simplify path surgery. */ cpio->destdir = malloc(strlen(destdir) + 8); strcpy(cpio->destdir, destdir); if (destdir[strlen(destdir) - 1] != '/') strcat(cpio->destdir, "/"); cpio->archive = archive_write_disk_new(); if (cpio->archive == NULL) cpio_errc(1, 0, "Failed to allocate archive object"); r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags); if (r != ARCHIVE_OK) cpio_errc(1, 0, archive_error_string(cpio->archive)); cpio->linkresolver = archive_entry_linkresolver_new(); archive_write_disk_set_standard_lookup(cpio->archive); lr = process_lines_init("-", cpio->line_separator); while ((p = process_lines_next(lr)) != NULL) file_to_archive(cpio, p); process_lines_free(lr); archive_entry_linkresolver_free(cpio->linkresolver); r = archive_write_close(cpio->archive); if (r != ARCHIVE_OK) cpio_errc(1, 0, archive_error_string(cpio->archive)); if (!cpio->quiet) { blocks = (archive_position_uncompressed(cpio->archive) + 511) / 512; fprintf(stderr, "%lu %s\n", blocks, blocks == 1 ? "block" : "blocks"); } archive_write_finish(cpio->archive); }
static struct archive *open_disk(int flags) { struct archive *disk; int r; disk = archive_write_disk_new(); if (!disk) { opkg_msg(ERROR, "Failed to create disk archive object.\n"); return NULL; } r = archive_write_disk_set_options(disk, flags); if (r == ARCHIVE_WARN) opkg_msg(NOTICE, "Warning when setting disk options: %s\n", archive_error_string(disk)); else if (r != ARCHIVE_OK) { opkg_msg(ERROR, "Failed to set disk options: %s\n", archive_error_string(disk)); goto err_cleanup; } r = archive_write_disk_set_standard_lookup(disk); if (r == ARCHIVE_WARN) opkg_msg(NOTICE, "Warning when setting user/group lookup functions: %s\n", archive_error_string(disk)); else if (r != ARCHIVE_OK) { opkg_msg(ERROR, "Failed to set user/group lookup functions: %s\n", archive_error_string(disk)); goto err_cleanup; } return disk; err_cleanup: archive_write_free(disk); return NULL; }
static void create_reg_file_win(struct archive_entry *ae, const char *msg) { static const char data[]="abcdefghijklmnopqrstuvwxyz"; struct archive *ad; struct stat st; char *p, *fname; size_t l; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); archive_write_disk_set_options(ad, ARCHIVE_EXTRACT_TIME); failure("%s", msg); archive_entry_set_size(ae, sizeof(data)); archive_entry_set_mtime(ae, 123456789, 0); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data))); assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); #if ARCHIVE_VERSION_NUMBER < 2000000 archive_write_finish(ad); #else assertEqualInt(0, archive_write_finish(ad)); #endif /* Test the entries on disk. */ l = strlen(archive_entry_pathname(ae)); fname = malloc(l + 1); assert(NULL != fname); strcpy(fname, archive_entry_pathname(ae)); /* Replace unusable characters in Windows to '_' */ for (p = fname; *p != '\0'; p++) if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || *p == '<' || *p == '>' || *p == '|') *p = '_'; assert(0 == stat(fname, &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); assertEqualInt(st.st_size, sizeof(data)); }
int packing_init(struct packing **pack, const char *path, pkg_formats format) { char archive_path[MAXPATHLEN]; const char *ext; if ((*pack = calloc(1, sizeof(struct packing))) == NULL) { pkg_emit_event(PKG_EVENT_MALLOC_ERROR, /*argc*/1, strerror(errno)); } (*pack)->aread = archive_read_disk_new(); archive_read_disk_set_standard_lookup((*pack)->aread); archive_read_disk_set_symlink_physical((*pack)->aread); (*pack)->entry = archive_entry_new(); if (!is_dir(path)) { (*pack)->awrite = archive_write_new(); archive_write_set_format_pax_restricted((*pack)->awrite); if ((ext = packing_set_format((*pack)->awrite, format)) == NULL) { archive_read_finish((*pack)->aread); archive_write_finish((*pack)->awrite); archive_entry_free((*pack)->entry); return EPKG_FATAL; /* error set by _set_format() */ } snprintf(archive_path, sizeof(archive_path), "%s.%s", path, ext); archive_write_open_filename((*pack)->awrite, archive_path); } else { /* pass mode directly write to the disk */ (*pack)->awrite = archive_write_disk_new(); archive_write_disk_set_options((*pack)->awrite, EXTRACT_ARCHIVE_FLAGS); } return (EPKG_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. 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; }
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; }
compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n) #endif { int *marker; int matched; int i; #if HAVE_SUN_ACL int e; aclent_t *acl_entry; #else int entry_id = ACL_FIRST_ENTRY; acl_entry_t acl_entry; #endif /* Count ACL entries in myacls array and allocate an indirect array. */ marker = malloc(sizeof(marker[0]) * n); if (marker == NULL) return; for (i = 0; i < n; i++) marker[i] = i; /* * Iterate over acls in system acl object, try to match each * one with an item in the myacls array. */ #if HAVE_SUN_ACL for(e = 0; e < acl->acl_cnt; e++) { acl_entry = &((aclent_t *)acl->acl_aclp)[e]; #else while (1 == acl_get_entry(acl, entry_id, &acl_entry)) { /* After the first time... */ entry_id = ACL_NEXT_ENTRY; #endif /* Search for a matching entry (tag and qualifier) */ for (i = 0, matched = 0; i < n && !matched; i++) { if (acl_match(acl_entry, &myacls[marker[i]])) { /* We found a match; remove it. */ marker[i] = marker[n - 1]; n--; matched = 1; } } /* TODO: Print out more details in this case. */ failure("ACL entry on file that shouldn't be there"); assert(matched == 1); } /* Dump entries in the myacls array that weren't in the system acl. */ for (i = 0; i < n; ++i) { failure(" ACL entry missing from file: " "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n", myacls[marker[i]].type, myacls[marker[i]].permset, myacls[marker[i]].tag, myacls[marker[i]].qual, myacls[marker[i]].name); assert(0); /* Record this as a failure. */ } free(marker); } #endif /* * Verify ACL restore-to-disk. This test is Platform-specific. */ DEFINE_TEST(test_acl_platform_posix1e_restore) { #if !HAVE_SUN_ACL && !HAVE_POSIX_ACL skipping("POSIX.1e ACLs are not supported on this platform"); #else /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ struct stat st; struct archive *a; struct archive_entry *ae; int n, fd; char *func; #if HAVE_SUN_ACL acl_t *acl, *acl2; #else acl_t acl; #endif /* * First, do a quick manual set/read of ACL data to * verify that the local filesystem does support ACLs. * If it doesn't, we'll simply skip the remaining tests. */ #if HAVE_SUN_ACL n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx"); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl != NULL); #endif /* Create a test file and try ACL on it. */ fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl); return; } #if HAVE_SUN_ACL n = facl_get(fd, 0, &acl2); if (n != 0) { close(fd); acl_free(acl); } if (errno == ENOSYS) { skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); if (acl2->acl_type != ACLENT_T) { acl_free(acl2); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } acl_free(acl2); func = "facl_set()"; n = facl_set(fd, acl); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl); #endif acl_free(acl); if (n != 0) { #if HAVE_SUN_ACL if (errno == ENOSYS) #else if (errno == EOPNOTSUPP || errno == EINVAL) #endif { close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } } failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); #if HAVE_SUN_ACL #endif close(fd); /* Create a write-to-disk object. */ assert(NULL != (a = archive_write_disk_new())); archive_write_disk_set_options(a, ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL); /* Populate an archive entry with some metadata, including ACL info */ ae = archive_entry_new(); assert(ae != NULL); archive_entry_set_pathname(ae, "test0"); archive_entry_set_mtime(ae, 123456, 7890); archive_entry_set_size(ae, 0); assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); archive_entry_free(ae); /* Close the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* Verify the data on disk. */ assertEqualInt(0, stat("test0", &st)); assertEqualInt(st.st_mtime, 123456); #if HAVE_SUN_ACL n = acl_get("test0", 0, &acl); failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl = acl_get_file("test0", ACL_TYPE_ACCESS); failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); #endif compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0])); acl_free(acl); #endif /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ } /* * Verify ACL read-from-disk. This test is Platform-specific. */ DEFINE_TEST(test_acl_platform_posix1e_read) { #if !HAVE_SUN_ACL && !HAVE_POSIX_ACL skipping("POSIX.1e ACLs are not supported on this platform"); #else struct archive *a; struct archive_entry *ae; int n, fd, flags, dflags; char *func, *acl_text; const char *acl1_text, *acl2_text, *acl3_text; #if HAVE_SUN_ACL acl_t *acl, *acl1, *acl2, *acl3; #else acl_t acl1, acl2, acl3; #endif /* * Manually construct a directory and two files with * different ACLs. This also serves to verify that ACLs * are supported on the local filesystem. */ /* Create a test file f1 with acl1 */ #if HAVE_SUN_ACL acl1_text = "user::rwx," "group::rwx," "other:rwx," "user:1:rw-," "group:15:r-x," "mask:rwx"; n = acl_fromtext(acl1_text, &acl1); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl1_text = "user::rwx\n" "group::rwx\n" "other::rwx\n" "user:1:rw-\n" "group:15:r-x\n" "mask::rwx"; acl1 = acl_from_text(acl1_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl1 != NULL); #endif fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl1); return; } #if HAVE_SUN_ACL /* Check if Solaris filesystem supports POSIX.1e ACLs */ n = facl_get(fd, 0, &acl); if (n != 0) close(fd); if (n != 0 && errno == ENOSYS) { acl_free(acl1); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); if (acl->acl_type != ACLENT_T) { acl_free(acl); acl_free(acl1); close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } func = "facl_set()"; n = facl_set(fd, acl1); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl1); #endif acl_free(acl1); if (n != 0) { #if HAVE_SUN_ACL if (errno == ENOSYS) #else if (errno == EOPNOTSUPP || errno == EINVAL) #endif { close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } } failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); close(fd); assertMakeDir("d", 0700); /* * Create file d/f1 with acl2 * * This differs from acl1 in the u:1: and g:15: permissions. * * This file deliberately has the same name but a different ACL. * Github Issue #777 explains how libarchive's directory traversal * did not always correctly enter directories before attempting * to read ACLs, resulting in reading the ACL from a like-named * file in the wrong directory. */ #if HAVE_SUN_ACL acl2_text = "user::rwx," "group::rwx," "other:---," "user:1:r--," "group:15:r--," "mask:rwx"; n = acl_fromtext(acl2_text, &acl2); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl2_text = "user::rwx\n" "group::rwx\n" "other::---\n" "user:1:r--\n" "group:15:r--\n" "mask::rwx"; acl2 = acl_from_text(acl2_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl2 != NULL); #endif fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl2); return; } #if HAVE_SUN_ACL func = "facl_set()"; n = facl_set(fd, acl2); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl2); #endif acl_free(acl2); if (n != 0) close(fd); failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); close(fd); /* Create nested directory d2 with default ACLs */ assertMakeDir("d/d2", 0755); #if HAVE_SUN_ACL acl3_text = "user::rwx," "group::r-x," "other:r-x," "user:2:r--," "group:16:-w-," "mask:rwx," "default:user::rwx," "default:user:1:r--," "default:group::r-x," "default:group:15:r--," "default:mask:rwx," "default:other:r-x"; n = acl_fromtext(acl3_text, &acl3); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl3_text = "user::rwx\n" "user:1:r--\n" "group::r-x\n" "group:15:r--\n" "mask::rwx\n" "other::r-x"; acl3 = acl_from_text(acl3_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl3 != NULL); #endif #if HAVE_SUN_ACL func = "acl_set()"; n = acl_set("d/d2", acl3); #else func = "acl_set_file()"; n = acl_set_file("d/d2", ACL_TYPE_DEFAULT, acl3); #endif acl_free(acl3); failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); /* Create a read-from-disk object. */ assert(NULL != (a = archive_read_disk_new())); assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, ".")); assert(NULL != (ae = archive_entry_new())); #if HAVE_SUN_ACL flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS; dflags = flags; #else flags = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; dflags = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; #endif /* Walk the dir until we see both of the files */ while (ARCHIVE_OK == archive_read_next_header2(a, ae)) { archive_read_disk_descend(a); if (strcmp(archive_entry_pathname(ae), "./f1") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, flags); assertEqualString(acl_text, acl1_text); free(acl_text); } else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, flags); assertEqualString(acl_text, acl2_text); free(acl_text); } else if (strcmp(archive_entry_pathname(ae), "./d/d2") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, dflags); assertEqualString(acl_text, acl3_text); free(acl_text); } } archive_entry_free(ae); assertEqualInt(ARCHIVE_OK, archive_free(a)); #endif }
static void extract(const char *filename, int do_extract, int flags) { struct archive *a; struct archive *ext; struct archive_entry *entry; int r; a = archive_read_new(); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); #ifndef NO_BZIP2_EXTRACT archive_read_support_filter_bzip2(a); #endif #ifndef NO_GZIP_EXTRACT archive_read_support_filter_gzip(a); #endif #ifndef NO_COMPRESS_EXTRACT archive_read_support_filter_compress(a); #endif #ifndef NO_TAR_EXTRACT archive_read_support_format_tar(a); #endif #ifndef NO_CPIO_EXTRACT archive_read_support_format_cpio(a); #endif #ifndef NO_LOOKUP archive_write_disk_set_standard_lookup(ext); #endif if (filename != NULL && strcmp(filename, "-") == 0) filename = NULL; if ((r = archive_read_open_filename(a, filename, 10240))) { errmsg(archive_error_string(a)); errmsg("\n"); exit(r); } for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { errmsg(archive_error_string(a)); errmsg("\n"); exit(1); } if (verbose && do_extract) msg("x "); if (verbose || !do_extract) msg(archive_entry_pathname(entry)); if (do_extract) { r = archive_write_header(ext, entry); if (r != ARCHIVE_OK) errmsg(archive_error_string(a)); else copy_data(a, ext); } if (verbose || !do_extract) msg("\n"); } archive_read_close(a); archive_read_free(a); exit(0); }
/*! \brief Extracts the selected .tar.gz archive to the selected folder, will try to create the target folder if it does not exist. * @param filePath Full path to selected archive. * @param targetFolderPath Full path to target folder. * @return Returns full path to the extracted archive, or empty QString if failed. */ QString ArchiveExtractor::extractFileToTargetFolder(QString filePath, QString targetFolderPath){ //check if the selected archive file exist QFile *selectedFile = new QFile(filePath); if(!selectedFile->exists()){ qDebug()<<"ERROR: File marked for decompression does not exist!"; delete selectedFile; return QString(""); } delete selectedFile; struct archive *a; struct archive *ext; struct archive_entry *entry; int r; // /* The "flags" argument selects optional behavior, 'OR' the flags you want. */ // /* Default: Do not try to set owner/group. */ //#define ARCHIVE_EXTRACT_OWNER (0x0001) // /* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */ //#define ARCHIVE_EXTRACT_PERM (0x0002) // /* Default: Do not restore mtime/atime. */ //#define ARCHIVE_EXTRACT_TIME (0x0004) // /* Default: Replace existing files. */ //#define ARCHIVE_EXTRACT_NO_OVERWRITE (0x0008) // /* Default: Try create first, unlink only if create fails with EEXIST. */ //#define ARCHIVE_EXTRACT_UNLINK (0x0010) // /* Default: Do not restore ACLs. */ //#define ARCHIVE_EXTRACT_ACL (0x0020) // /* Default: Do not restore fflags. */ //#define ARCHIVE_EXTRACT_FFLAGS (0x0040) // /* Default: Do not restore xattrs. */ //#define ARCHIVE_EXTRACT_XATTR (0x0080) // /* Default: Do not try to guard against extracts redirected by symlinks. */ // /* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */ //#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (0x0100) // /* Default: Do not reject entries with '..' as path elements. */ //#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (0x0200) // /* Default: Create parent directories as needed. */ //#define ARCHIVE_EXTRACT_NO_AUTODIR (0x0400) // /* Default: Overwrite files, even if one on disk is newer. */ //#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800) // /* Detect blocks of 0 and write holes instead. */ //#define ARCHIVE_EXTRACT_SPARSE (0x1000) // /* Default: Do not restore Mac extended metadata. */ // /* This has no effect except on Mac OS. */ //#define ARCHIVE_EXTRACT_MAC_METADATA (0x2000) int flags = 0; // flags |= ARCHIVE_EXTRACT_TIME; // flags |= ARCHIVE_EXTRACT_NO_AUTODIR; // flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; QFileInfo *fileInfo = new QFileInfo(filePath); // qDebug()<<"resolved filename: "<<fileInfo->fileName(); delete fileInfo; //MEMORY LEAK!!! (Pointers be dangerous, man. :) // const char *filename = fileInfo->fileName().toUtf8().constData(); //AVOID IT BY CONVERTING TO A QBYTEARRAY FIRST! QByteArray byteArray = filePath.toUtf8(); const char *filename = byteArray.constData(); //That's better :D //toggle extraction bool do_extract = true; a = archive_read_new(); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); //tuned for .tar.gz archive_read_support_filter_gzip(a); archive_read_support_format_gnutar(a); if((r = archive_read_open_filename(a, filename, 10240)) ){ errmsg(archive_error_string(a)); } for(;;){ r = archive_read_next_header(a, &entry); if(r == ARCHIVE_EOF) break; if(r != ARCHIVE_OK){ errmsg(archive_error_string(a)); } if (verbose || !do_extract){ qDebug()<<"Detected files in archive: "; msg(archive_entry_pathname(entry)); } QString currentPath(archive_entry_pathname( entry )); qDebug()<<currentPath; QDir targetFolder(targetFolderPath); if(!targetFolder.exists()){//target folder does not exist //attempt to create it if(!targetFolder.mkpath(targetFolderPath)){//failed to create target folder //break procedure qDebug()<<"ERROR: Target folder does not exist and cannot be created"; return QString(""); } } QString newPath = targetFolderPath + currentPath; qDebug()<<"newPath: " << newPath; archive_entry_set_pathname( entry, newPath.toUtf8().constData() ); if (verbose && do_extract){ // msg("About to start extracting\n"); } if (do_extract){ qDebug()<<"Extracting..."; r = archive_write_header(ext, entry); if (r != ARCHIVE_OK) errmsg(archive_error_string(a)); else copy_data(a, ext); std::string returnPath; returnPath = archive_entry_pathname(entry); qDebug()<<"File extracted: " << QString::fromStdString(returnPath); archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); return QString::fromStdString( returnPath ); } } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); return QString(""); }
static void extract_archive(const char *filename, const char *output) { struct archive *a; struct archive *ext; struct archive_entry *entry; int flags; int r; flags = ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_SECURE_NODOTDOT; a = archive_read_new(); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_read_support_compression_bzip2(a); #else archive_read_support_filter_bzip2(a); #endif archive_read_support_format_tar(a); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); r = archive_read_open_file(a, filename, 10240); if (r) { std::string msg = extract_archive_error(filename, output, a); archive_read_close(a); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_read_finish(a); #else archive_read_free(a); #endif throw utils::InternalError(msg); } for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) { break; } if (r != ARCHIVE_OK) { std::string msg = extract_archive_error(filename, output, a); archive_read_close(a); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_read_finish(a); #else archive_read_free(a); #endif archive_write_close(ext); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_write_finish(ext); #else archive_write_free(ext); #endif throw utils::InternalError(msg); } if (r < ARCHIVE_WARN) { break; } r = archive_write_header(ext, entry); if (r != ARCHIVE_OK) { std::string msg = extract_archive_error(filename, output, a); archive_read_close(a); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_read_finish(a); #else archive_read_free(a); #endif archive_write_close(ext); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_write_finish(ext); #else archive_write_free(ext); #endif throw utils::InternalError(msg); } else { r = copy_data(a, ext); if (r != ARCHIVE_OK) { std::string msg = extract_archive_error(filename, output, a); archive_read_close(a); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_read_finish(a); #else archive_read_free(a); #endif archive_write_close(ext); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_write_finish(ext); #else archive_write_free(ext); #endif throw utils::InternalError(msg); } } } archive_read_close(a); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_read_finish(a); #else archive_read_free(a); #endif archive_write_close(ext); #if ARCHIVE_VERSION_NUMBER < 4000000 archive_write_finish(ext); #else archive_write_free(ext); #endif }
//******************************************************************************************************** void read_archive(const char* const infile, const char* const extractFolder){ // Strongly inspired by // https://github.com/libarchive/libarchive/wiki/Examples#A_Complete_Extractor //printf("Opening archive '%s' for extracting to folder '%s'...\n",infile,extractFolder); //Check that the archive exists //Check that the folder exists, if not then create it struct archive* a = archive_read_new(); archive_read_support_format_zip(a); struct archive* ext = archive_write_disk_new(); archive_write_disk_set_options(ext,ARCHIVE_EXTRACT_TIME|ARCHIVE_EXTRACT_PERM|ARCHIVE_EXTRACT_ACL|ARCHIVE_EXTRACT_FFLAGS); archive_write_disk_set_standard_lookup(ext); int err; err = archive_read_open_filename(a, infile, 10240); if (err != ARCHIVE_OK) { fprintf(stderr, "CRITICAL ERROR in read_archive(): When opening archive '%s', err=%i\n",infile,err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a)); exit(EXIT_FAILURE); } struct archive_entry *entry; const int fcount_max = 1000; char fcompleted=0; //C-Boolean for(int fcount=0; fcount<fcount_max;fcount++){ err = archive_read_next_header(a,&entry); if (err == ARCHIVE_EOF){ fcompleted=1; break; } else if (err != ARCHIVE_OK){ fprintf(stderr, "CRITICAL ERROR in read_archive(): When reading archive, err=%i\n",err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a)); exit(EXIT_FAILURE); } //printf("Found file: '%s'\n",archive_entry_pathname(entry)); //Avoid clobbering files in current directory - solution from // http://stackoverflow.com/questions/4496001/libarchive-to-extract-to-a-specified-folder char newPath[PATH_MAX]; int buff_used = snprintf(newPath, PATH_MAX, "%s/%s",extractFolder,archive_entry_pathname(entry)); if (buff_used >= PATH_MAX || buff_used < 0){ fprintf(stderr, "CRITICAL ERROR in read_archive(): Buffer overflow or other error when creating the path.\n"); fprintf(stderr, "CRITICAL ERROR in read_archive(): buff_used=%i\n",buff_used); exit(EXIT_FAILURE); } archive_entry_set_pathname(entry,newPath); err = archive_write_header(ext, entry); if (err != ARCHIVE_OK){ fprintf(stderr, "CRITICAL ERROR in read_archive(): when extracting archive (creating new file), err=%i\n",err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(ext)); exit(EXIT_FAILURE); } //Write the data! const void* buff; size_t size; la_int64_t offset; const int bcount_max = 100000000; char bcompleted = 0; //C boolean for (int bcount=0; bcount<bcount_max;bcount++){ err = archive_read_data_block(a,&buff,&size, &offset); if ( err == ARCHIVE_EOF ) { bcompleted=1; break; } else if (err != ARCHIVE_OK){ fprintf(stderr, "CRITICAL ERROR in read_archive(): When extracting archive (reading data), err=%i\n",err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a)); exit(EXIT_FAILURE); } err = archive_write_data_block(ext,buff,size,offset); if (err != ARCHIVE_OK){ fprintf(stderr, "CRITICAL ERROR in read_archive(): When extracting archive (writing data), err=%i\n",err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a)); exit(EXIT_FAILURE); } } if (!bcompleted){ fprintf(stderr, "CRITICAL ERROR in read_archive(): The file writing block loop was aborted by the infinite loop guard\n"); exit(EXIT_FAILURE); } err=archive_write_finish_entry(ext); if (err != ARCHIVE_OK) { fprintf(stderr, "CRITICAL ERROR in read_archive(): When extracting archive (closing new file), err=%i\n",err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(ext)); exit(EXIT_FAILURE); } } archive_read_close(a); err=archive_read_free(a); if (err != ARCHIVE_OK){ fprintf(stderr, "CRITICAL ERROR in read_archive(): When calling archive_read_free(a), err=%i\n",err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a)); exit(EXIT_FAILURE); } archive_write_close(ext); err = archive_write_free(ext); if (err != ARCHIVE_OK){ fprintf(stderr, "CRITICAL ERROR in read_archive(): When calling archive_read_free(ext), err=%i\n",err); fprintf(stderr, "CRITICAL ERROR in read_archive(): %s\n",archive_error_string(a)); exit(EXIT_FAILURE); } if (!fcompleted) { fprintf(stderr, "CRITICAL ERROR in read_archive(): The file header loop was aborted by the infinite loop guard\n"); exit(EXIT_FAILURE); } }
bool extractXZ(FILE *sfp, std::string dest) { struct archive *a; struct archive *ext; struct archive_entry *entry; int flags; int r; /* Select which attributes we want to restore. */ flags = ARCHIVE_EXTRACT_TIME; flags |= ARCHIVE_EXTRACT_PERM; flags |= ARCHIVE_EXTRACT_ACL; flags |= ARCHIVE_EXTRACT_FFLAGS; a = archive_read_new(); archive_read_support_format_all(a); archive_read_support_filter_all(a); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); if ((r = archive_read_open_FILE(a, sfp))) { std::cout<<archive_error_string(ext)<<std::endl; return false; } for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(a)); if (r < ARCHIVE_WARN) { fprintf(stderr, "warn 1\n"); return false; } std::string path = archive_entry_pathname(entry); //std::cout<<"old path: "<< path<<std::endl; archive_entry_set_pathname(entry, (dest + "/" + path).c_str()); r = archive_write_header(ext, entry); if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(ext)); else if (archive_entry_size(entry) > 0) { r = copy_data(a, ext); if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(ext)); if (r < ARCHIVE_WARN) { fprintf(stderr, "warn 2\n"); return false; } } r = archive_write_finish_entry(ext); if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(ext)); if (r < ARCHIVE_WARN) { fprintf(stderr, "warn 3\n"); return false; } } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); return true; }
static void mode_in(struct cpio *cpio) { struct archive *a; struct archive_entry *entry; struct archive *ext; const char *destpath; int r; ext = archive_write_disk_new(); if (ext == NULL) lafe_errc(1, 0, "Couldn't allocate restore object"); r = archive_write_disk_set_options(ext, cpio->extract_flags); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(ext)); a = archive_read_new(); if (a == NULL) lafe_errc(1, 0, "Couldn't allocate archive object"); archive_read_support_compression_all(a); archive_read_support_format_all(a); if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block)) lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { lafe_errc(1, archive_errno(a), "%s", archive_error_string(a)); } if (lafe_excluded(cpio->matching, archive_entry_pathname(entry))) continue; if (cpio->option_rename) { destpath = cpio_rename(archive_entry_pathname(entry)); archive_entry_set_pathname(entry, destpath); } else destpath = archive_entry_pathname(entry); if (destpath == NULL) continue; if (cpio->verbose) fprintf(stdout, "%s\n", destpath); if (cpio->uid_override >= 0) archive_entry_set_uid(entry, cpio->uid_override); if (cpio->gid_override >= 0) archive_entry_set_gid(entry, cpio->gid_override); r = archive_write_header(ext, entry); if (r != ARCHIVE_OK) { fprintf(stderr, "%s: %s\n", archive_entry_pathname(entry), archive_error_string(ext)); } else if (archive_entry_size(entry) > 0) { r = extract_data(a, ext); if (r != ARCHIVE_OK) cpio->return_value = 1; } } r = archive_read_close(a); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(a)); r = archive_write_close(ext); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(ext)); if (!cpio->quiet) { int64_t blocks = (archive_position_uncompressed(a) + 511) / 512; fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } archive_read_finish(a); archive_write_finish(ext); exit(cpio->return_value); }
void Package::readPackageFile(const std::string &package_path) { if (!package_path.empty()) mPackagePath = package_path; boost::filesystem::path unpacked_dir = mWorkDir; unpacked_dir /= mPackagePath.stem(); mUnpackedDir = unpacked_dir; const void *buf; int r; struct archive *a = archive_read_new(); struct archive_entry *entry; archive_read_support_compression_bzip2(a); archive_read_support_format_tar(a); struct archive *ext = archive_write_disk_new(); int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS; archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); r = archive_read_open_filename(a, package_path.c_str(), 16384); if (r != ARCHIVE_OK) { archive_read_free(a); archive_write_free(ext); throw Exception(std::string("archive_read_open_filename() failed for file: ") + package_path); } while (true) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) { break; } if (r < ARCHIVE_OK) { std::cerr << archive_error_string(ext) << std::endl; } if (r < ARCHIVE_WARN) { archive_read_free(a); archive_write_free(ext); throw Exception(std::string("archive_read_next_header() failed:") + archive_error_string(a)); } std::cout << std::string("extract: ") << archive_entry_pathname(entry) << std::endl; archive_entry_set_pathname(entry, (mUnpackedDir.string() + std::string("/") + archive_entry_pathname(entry)).c_str()); r = archive_write_header(ext, entry); if (r < ARCHIVE_OK) { archive_read_free(a); archive_write_free(ext); throw Exception(std::string("archive_write_header() failed:") + archive_error_string(ext)); } else if (archive_entry_size(entry) > 0) { size_t size; int64_t offset; while (true) { r = archive_read_data_block(a, &buf, &size, &offset); if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_WARN) { archive_read_free(a); archive_write_free(ext); throw Exception(std::string(archive_error_string(ext))); } if (r < ARCHIVE_OK) { std::cerr << archive_error_string(ext) << std::endl; break; } r = archive_write_data_block(ext, buf, size, offset); if (r < ARCHIVE_WARN) { archive_read_free(a); archive_write_free(ext); throw Exception(std::string(archive_error_string(ext))); } if (r < ARCHIVE_OK) { std::cerr << archive_error_string(ext) << std::endl; break; } } r = archive_write_finish_entry(ext); if (r < ARCHIVE_OK) std::cerr << archive_error_string(ext) << std::endl; if (r < ARCHIVE_WARN) { archive_read_free(a); archive_write_free(ext); throw Exception(std::string(archive_error_string(ext))); } } } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); }
RESULTCODE ArchiveProcessorImpl::Decompress() { const char* tpath = GetArchivePath(); if(tpath==NULL) { return AG_FAILURE; } struct archive *a; struct archive *ext; struct archive_entry *entry; int flags; int r; /* Select which attributes we want to restore. */ flags = ARCHIVE_EXTRACT_TIME; flags |= ARCHIVE_EXTRACT_PERM; flags |= ARCHIVE_EXTRACT_ACL; flags |= ARCHIVE_EXTRACT_FFLAGS; a = archive_read_new(); archive_read_support_format_all(a); archive_read_support_compression_all(a); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); if((r = archive_read_open_filename(a, tpath, 10240))) { return AG_FAILURE; } while(true) { r = archive_read_next_header(a, &entry); if( r== ARCHIVE_EOF) { break; } if( r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(a)); } if( r< ARCHIVE_WARN) { break; } r = archive_write_header(ext, entry); if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(ext)); } else if (archive_entry_size(entry) > 0) { r = copy_data(a, ext); } if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(ext)); } if (r < ARCHIVE_WARN) { break; } r = archive_write_finish_entry(ext); if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(ext)); } if(r < ARCHIVE_WARN) { break; } } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); //return r==ARCHIVE_OK ? AG_SUCCESS : AG_FAILURE; return AG_SUCCESS; }
static bool extract_theme(const std::string &path, const std::string &target, const std::string &theme_name) { mb::autoclose::archive in(archive_read_new(), archive_read_free); if (!in) { LOGE("%s: Out of memory when creating archive reader", __FUNCTION__); return false; } mb::autoclose::archive out(archive_write_disk_new(), archive_write_free); if (!out) { LOGE("%s: Out of memory when creating disk writer", __FUNCTION__); return false; } archive_read_support_format_zip(in.get()); // Set up disk writer parameters. We purposely don't extract any file // metadata int flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_SECURE_NODOTDOT; archive_write_disk_set_standard_lookup(out.get()); archive_write_disk_set_options(out.get(), flags); if (archive_read_open_filename(in.get(), path.c_str(), 10240) != ARCHIVE_OK) { LOGE("%s: Failed to open file: %s", path.c_str(), archive_error_string(in.get())); return false; } archive_entry *entry; int ret; std::string target_path; std::string common_prefix("theme/common/"); std::string theme_prefix("theme/"); theme_prefix += theme_name; theme_prefix += '/'; while (true) { ret = archive_read_next_header(in.get(), &entry); if (ret == ARCHIVE_EOF) { break; } else if (ret == ARCHIVE_RETRY) { LOGW("%s: Retrying header read", path.c_str()); continue; } else if (ret != ARCHIVE_OK) { LOGE("%s: Failed to read header: %s", path.c_str(), archive_error_string(in.get())); return false; } const char *path = archive_entry_pathname(entry); if (!path || !*path) { LOGE("%s: Header has null or empty filename", path); return false; } const char *suffix; if (mb::util::starts_with(path, common_prefix)) { suffix = path + common_prefix.size(); } else if (mb::util::starts_with(path, theme_prefix)) { suffix = path + theme_prefix.size(); } else { LOGV("Skipping: %s", path); continue; } // Build path target_path = target; if (target_path.back() != '/' && *suffix != '/') { target_path += '/'; } target_path += suffix; LOGV("Extracting: %s -> %s", path, target_path.c_str()); archive_entry_set_pathname(entry, target_path.c_str()); // Extract file ret = archive_read_extract2(in.get(), entry, out.get()); if (ret != ARCHIVE_OK) { LOGE("%s: %s", archive_entry_pathname(entry), archive_error_string(in.get())); return false; } } if (archive_read_close(in.get()) != ARCHIVE_OK) { LOGE("%s: Failed to close file: %s", path.c_str(), archive_error_string(in.get())); return false; } return true; }
bool libarchive_tar_extract(const std::string &filename, const std::string &target, const std::vector<std::string> &patterns) { if (target.empty()) { LOGE("%s: Invalid target path for extraction", target.c_str()); return false; } autoclose::archive matcher(archive_match_new(), archive_match_free); if (!matcher) { LOGE("%s: Out of memory when creating matcher", __FUNCTION__); return false; } autoclose::archive in(archive_read_new(), archive_read_free); if (!in) { LOGE("%s: Out of memory when creating archive reader", __FUNCTION__); return false; } autoclose::archive out(archive_write_disk_new(), archive_write_free); if (!out) { LOGE("%s: Out of memory when creating disk writer", __FUNCTION__); return false; } // Set up matcher parameters for (const std::string &pattern : patterns) { if (archive_match_include_pattern( matcher.get(), pattern.c_str()) != ARCHIVE_OK) { LOGE("Invalid pattern: %s", pattern.c_str()); return false; } } // Set up archive reader parameters //archive_read_support_format_gnutar(in.get()); archive_read_support_format_tar(in.get()); //archive_read_support_filter_bzip2(in.get()); //archive_read_support_filter_gzip(in.get()); //archive_read_support_filter_xz(in.get()); // Set up disk writer parameters archive_write_disk_set_standard_lookup(out.get()); archive_write_disk_set_options(out.get(), LIBARCHIVE_DISK_WRITER_FLAGS); if (archive_read_open_filename( in.get(), filename.c_str(), 10240) != ARCHIVE_OK) { LOGE("%s: Failed to open file: %s", filename.c_str(), archive_error_string(in.get())); return false; } archive_entry *entry; int ret; std::string target_path; while (true) { ret = archive_read_next_header(in.get(), &entry); if (ret == ARCHIVE_EOF) { break; } else if (ret == ARCHIVE_RETRY) { LOGW("%s: Retrying header read", filename.c_str()); continue; } else if (ret != ARCHIVE_OK) { LOGE("%s: Failed to read header: %s", filename.c_str(), archive_error_string(in.get())); return false; } const char *path = archive_entry_pathname(entry); if (!path || !*path) { LOGE("%s: Header has null or empty filename", filename.c_str()); return false; } LOGV("%s", path); // Build path target_path = target; if (target_path.back() != '/' && *path != '/') { target_path += '/'; } target_path += path; archive_entry_set_pathname(entry, target_path.c_str()); // Check pattern matches if (archive_match_excluded(matcher.get(), entry)) { continue; } // Extract file ret = archive_read_extract2(in.get(), entry, out.get()); if (ret != ARCHIVE_OK) { LOGE("%s: %s", archive_entry_pathname(entry), archive_error_string(in.get())); return false; } } if (archive_read_close(in.get()) != ARCHIVE_OK) { LOGE("%s: %s", filename.c_str(), archive_error_string(in.get())); return false; } // Check that all patterns were matched const char *pattern; while ((ret = archive_match_path_unmatched_inclusions_next( matcher.get(), &pattern)) == ARCHIVE_OK) { LOGE("%s: Pattern not matched: %s", filename.c_str(), pattern); } if (ret != ARCHIVE_EOF) { LOGE("%s: %s", filename.c_str(), archive_error_string(matcher.get())); return false; } return archive_match_path_unmatched_inclusions(matcher.get()) == 0; }