/*! * \brief Copy sparse file on disk to an archive * * \see tar/write.c from libarchive's source code */ bool libarchive_copy_data_disk_to_archive(archive *in, archive *out, archive_entry *entry) { size_t bytes_read; ssize_t bytes_written; int64_t offset; int64_t progress = 0; char null_buf[64 * 1024]; const void *buf; int ret; memset(null_buf, 0, sizeof(null_buf)); while ((ret = archive_read_data_block( in, &buf, &bytes_read, &offset)) == ARCHIVE_OK) { if (offset > progress) { int64_t sparse = offset - progress; size_t ns; while (sparse > 0) { if (sparse > (int64_t) sizeof(null_buf)) { ns = sizeof(null_buf); } else { ns = (size_t) sparse; } bytes_written = archive_write_data(out, null_buf, ns); if (bytes_written < 0) { LOGE("%s: %s", archive_entry_pathname(entry), archive_error_string(out)); return false; } if ((size_t) bytes_written < ns) { LOGE("%s: Truncated write", archive_entry_pathname(entry)); return false; } progress += bytes_written; sparse -= bytes_written; } } bytes_written = archive_write_data(out, buf, bytes_read); if (bytes_written < 0) { LOGE("%s: %s", archive_entry_pathname(entry), archive_error_string(out)); return false; } if ((size_t) bytes_written < bytes_read) { LOGE("%s: Truncated write", archive_entry_pathname(entry)); return false; } progress += bytes_written; } if (ret != ARCHIVE_EOF) { LOGE("%s: %s", archive_entry_pathname(entry), archive_error_string(in)); return false; } return true; }
/* Helper function to copy file to archive. */ static int copy_file_data_block(struct bsdtar *bsdtar, struct archive *a, struct archive *in_a, struct archive_entry *entry) { size_t bytes_read; ssize_t bytes_written; int64_t offset, progress = 0; char *null_buff = NULL; const void *buff; int r; while ((r = archive_read_data_block(in_a, &buff, &bytes_read, &offset)) == ARCHIVE_OK) { if (need_report()) report_write(bsdtar, a, entry, progress); if (offset > progress) { int64_t sparse = offset - progress; size_t ns; if (null_buff == NULL) { null_buff = bsdtar->buff; memset(null_buff, 0, bsdtar->buff_size); } while (sparse > 0) { if (sparse > (int64_t)bsdtar->buff_size) ns = bsdtar->buff_size; else ns = (size_t)sparse; bytes_written = archive_write_data(a, null_buff, ns); if (bytes_written < 0) { /* Write failed; this is bad */ lafe_warnc(0, "%s", archive_error_string(a)); return (-1); } if ((size_t)bytes_written < ns) { /* Write was truncated; warn but * continue. */ lafe_warnc(0, "%s: Truncated write; file may " "have grown while being archived.", archive_entry_pathname(entry)); return (0); } progress += bytes_written; sparse -= bytes_written; } } bytes_written = archive_write_data(a, buff, bytes_read); if (bytes_written < 0) { /* Write failed; this is bad */ lafe_warnc(0, "%s", archive_error_string(a)); return (-1); } if ((size_t)bytes_written < bytes_read) { /* Write was truncated; warn but continue. */ lafe_warnc(0, "%s: Truncated write; file may have grown " "while being archived.", archive_entry_pathname(entry)); return (0); } progress += bytes_written; } if (r < ARCHIVE_WARN) { lafe_warnc(archive_errno(a), "%s", archive_error_string(a)); return (-1); } return (0); }
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); }
static GdkPixbuf* load_pixbuf_from_archive(const char* archive, const char* file) { if (archive == NULL || file == NULL) { return NULL; } struct archive* a = archive_read_new(); if (a == NULL) { return NULL; } archive_read_support_filter_all(a); archive_read_support_format_all(a); int r = archive_read_open_filename(a, archive, LIBARCHIVE_BUFFER_SIZE); if (r != ARCHIVE_OK) { return NULL; } struct archive_entry* entry = NULL; while ((r = archive_read_next_header(a, &entry)) != ARCHIVE_EOF) { if (r < ARCHIVE_WARN) { archive_read_close(a); archive_read_free(a); return NULL; } const char* path = archive_entry_pathname(entry); if (compare_path(path, file) != 0) { continue; } GInputStream* is = g_memory_input_stream_new(); if (is == NULL) { archive_read_close(a); archive_read_free(a); return NULL; } GMemoryInputStream* mis = G_MEMORY_INPUT_STREAM(is); size_t size = 0; const void* buf = NULL; off_t offset = 0; while ((r = archive_read_data_block(a, &buf, &size, &offset)) != ARCHIVE_EOF) { if (r < ARCHIVE_WARN) { archive_read_close(a); archive_read_free(a); g_object_unref(mis); return NULL; } if (size == 0) { continue; } void* tmp = g_malloc0(size); if (tmp == NULL) { archive_read_close(a); archive_read_free(a); g_object_unref(mis); return NULL; } memcpy(tmp, buf, size); g_memory_input_stream_add_data(mis, tmp, size, g_free); } GdkPixbuf* pixbuf = gdk_pixbuf_new_from_stream(is, NULL, NULL); if (pixbuf == NULL) { archive_read_close(a); archive_read_free(a); g_object_unref(mis); return NULL; } archive_read_close(a); archive_read_free(a); g_object_unref(mis); return pixbuf; } archive_read_close(a); archive_read_free(a); return NULL; }
static void verify_archive_file(const char *name, struct archive_contents *ac) { struct archive_entry *ae; int err; /* data, size, offset of next expected block. */ struct contents expect; /* data, size, offset of block read from archive. */ struct contents actual; const void *p; struct archive *a; extract_reference_file(name); assert((a = archive_read_new()) != NULL); assert(0 == archive_read_support_compression_all(a)); assert(0 == archive_read_support_format_tar(a)); failure("Can't open %s", name); assert(0 == archive_read_open_filename(a, name, 3)); while (ac->filename != NULL) { struct contents *cts = ac->contents; if (!assertEqualIntA(a, 0, archive_read_next_header(a, &ae))) { assert(0 == archive_read_finish(a)); return; } failure("Name mismatch in archive %s", name); assertEqualString(ac->filename, archive_entry_pathname(ae)); expect = *cts++; while (0 == (err = archive_read_data_block(a, &p, &actual.s, &actual.o))) { actual.d = p; while (actual.s > 0) { char c = *actual.d; if(actual.o < expect.o) { /* * Any byte before the expected * data must be NULL. */ failure("%s: pad at offset %d " "should be zero", name, actual.o); assertEqualInt(c, 0); } else if (actual.o == expect.o) { /* * Data at matching offsets must match. */ assertEqualInt(c, *expect.d); expect.d++; expect.o++; expect.s--; /* End of expected? step to next expected. */ if (expect.s <= 0) expect = *cts++; } else { /* * We found data beyond that expected. */ failure("%s: Unexpected trailing data", name); assert(actual.o <= expect.o); archive_read_finish(a); return; } actual.d++; actual.o++; actual.s--; } } failure("%s: should be end of entry", name); assertEqualIntA(a, err, ARCHIVE_EOF); failure("%s: Size returned at EOF must be zero", name); assertEqualInt((int)actual.s, 0); #if ARCHIVE_VERSION_NUMBER < 1009000 /* libarchive < 1.9 doesn't get this right */ skipping("offset of final sparse chunk"); #else failure("%s: Offset of final empty chunk must be same as file size", name); assertEqualInt(actual.o, expect.o); #endif /* Step to next file description. */ ++ac; } err = archive_read_next_header(a, &ae); assertEqualIntA(a, ARCHIVE_EOF, err); assert(0 == archive_read_close(a)); #if ARCHIVE_VERSION_NUMBER < 2000000 archive_read_finish(a); #else assert(0 == archive_read_finish(a)); #endif }
/* ArchiveReader::getNextEntry {{{ * */ ZEND_METHOD(ArchiveReader, getNextEntry) { zval *this = getThis(); archive_file_t *arch; int result, error_num, resource_id; const char *error_string; zend_bool fetch_entry_data = 0; archive_entry_t *entry; struct archive_entry *current_entry; size_t len; off_t offset; char *buf; zend_error_handling error_handling; zend_replace_error_handling(EH_THROW, ce_ArchiveException, &error_handling TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &fetch_entry_data) == FAILURE) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } if (!_archive_get_fd(this, &arch TSRMLS_CC)) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } if (arch->struct_state == ARCHIVE_OK) { result = archive_read_next_header(arch->arch, ¤t_entry); arch->struct_state = result; entry = (archive_entry_t *) emalloc(sizeof(archive_entry_t)); entry->entry = current_entry; entry->data = NULL; entry->filename = NULL; entry->resolved_filename = NULL; entry->data_len = 0; arch->current_entry = entry; } else { zend_restore_error_handling(&error_handling TSRMLS_CC); RETURN_FALSE; } if (result && result != ARCHIVE_EOF) { arch->current_entry = NULL; error_num = archive_errno(arch->arch); error_string = archive_error_string(arch->arch); efree(entry); if (error_num && error_string) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read file %s: error #%d, %s", arch->filename, error_num, error_string); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read file %s: unknown error %d", arch->filename, result); } zend_restore_error_handling(&error_handling TSRMLS_CC); return; } if (result == ARCHIVE_EOF) { arch->current_entry = NULL; efree(entry); zend_restore_error_handling(&error_handling TSRMLS_CC); RETURN_FALSE; } object_init_ex(return_value, ce_ArchiveEntry); if (fetch_entry_data) { while ((result = archive_read_data_block(arch->arch, (const void **)&buf, &len, &offset)) == ARCHIVE_OK) { entry->data = erealloc(entry->data, entry->data_len + len + 1); memcpy(entry->data + entry->data_len, buf, len); entry->data_len += len; } if (result && result != ARCHIVE_EOF) { error_num = archive_errno(arch->arch); error_string = archive_error_string(arch->arch); efree(entry); if (error_num && error_string) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read file %s: error #%d, %s", arch->filename, error_num, error_string); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read file %s: unknown error %d", arch->filename, result); } zend_restore_error_handling(&error_handling TSRMLS_CC); return; } } if (entry->entry) { resource_id = zend_list_insert(entry,le_archive_entry); add_property_resource(return_value, "entry", resource_id); } zend_restore_error_handling(&error_handling TSRMLS_CC); }
int archive_extract_tar_bzip2(void) { struct archive *a; struct archive *ext; int r = 0; int flags = 0; int error = 0; a = archive_read_new(); archive_read_support_format_tar(a); archive_read_support_compression_bzip2(a); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); if ((r = archive_read_open_file(a, NULL, 10240))) { fprintf(stderr, "archiving: %s", archive_error_string(a)); error = r; } else { for (;;) { struct archive_entry *entry; r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) { break; } if (r != ARCHIVE_OK) { fprintf(stderr, "archiving: %s", archive_error_string(a)); error = 1; break; } if (archive_write_header(ext, entry) != ARCHIVE_OK) { fprintf(stderr, "archiving: %s", archive_error_string(ext)); } else { const void *buff; size_t size; off_t offset; for (;;) { r = archive_read_data_block(a, &buff, &size, &offset); if (r == ARCHIVE_EOF) { r = ARCHIVE_OK; break; } if (r != ARCHIVE_OK) { fprintf(stderr, "archiving: %s", archive_error_string(ext)); break; } r = archive_write_data_block(ext, buff, size, offset); if (r != ARCHIVE_OK) { fprintf(stderr, "archiving: %s", archive_error_string(ext)); break; } } if (r != ARCHIVE_OK) { error = 1; break; } r = archive_write_finish_entry(ext); if (r != ARCHIVE_OK) { fprintf(stderr, "archiving: %s", archive_error_string(ext)); error = 1; break; } } } } archive_read_close(a); archive_read_finish(a); return error; }
static void test_fuzz(const struct files *filesets) { const void *blk; size_t blk_size; int64_t blk_offset; int n; for (n = 0; filesets[n].names != NULL; ++n) { const size_t buffsize = 30000000; struct archive_entry *ae; struct archive *a; char *rawimage = NULL, *image = NULL, *tmp = NULL; size_t size = 0, oldsize = 0; int i, q; extract_reference_files(filesets[n].names); if (filesets[n].uncompress) { int r; /* Use format_raw to decompress the data. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_raw(a)); r = archive_read_open_filenames(a, filesets[n].names, 16384); if (r != ARCHIVE_OK) { archive_read_free(a); if (filesets[n].names[0] == NULL || filesets[n].names[1] == NULL) { skipping("Cannot uncompress fileset"); } else { skipping("Cannot uncompress %s", filesets[n].names[0]); } continue; } assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); rawimage = malloc(buffsize); size = archive_read_data(a, rawimage, buffsize); assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); assert(size > 0); if (filesets[n].names[0] == NULL || filesets[n].names[1] == NULL) { failure("Internal buffer is not big enough for " "uncompressed test files"); } else { failure("Internal buffer is not big enough for " "uncompressed test file: %s", filesets[n].names[0]); } if (!assert(size < buffsize)) { free(rawimage); continue; } } else { for (i = 0; filesets[n].names[i] != NULL; ++i) { tmp = slurpfile(&size, filesets[n].names[i]); rawimage = (char *)realloc(rawimage, oldsize + size); memcpy(rawimage + oldsize, tmp, size); oldsize += size; size = oldsize; free(tmp); if (!assert(rawimage != NULL)) continue; } } if (size == 0) continue; image = malloc(size); assert(image != NULL); if (image == NULL) { free(rawimage); return; } srand((unsigned)time(NULL)); for (i = 0; i < 1000; ++i) { FILE *f; int j, numbytes, trycnt; /* Fuzz < 1% of the bytes in the archive. */ memcpy(image, rawimage, size); q = (int)size / 100; if (q < 4) q = 4; numbytes = (int)(rand() % q); for (j = 0; j < numbytes; ++j) image[rand() % size] = (char)rand(); /* Save the messed-up image to a file. * If we crash, that file will be useful. */ for (trycnt = 0; trycnt < 3; trycnt++) { f = fopen("after.test.failure.send.this.file." "to.libarchive.maintainers.with.system.details", "wb"); if (f != NULL) break; #if defined(_WIN32) && !defined(__CYGWIN__) /* * Sometimes previous close operation does not completely * end at this time. So we should take a wait while * the operation running. */ Sleep(100); #endif } assertEqualInt((size_t)size, fwrite(image, 1, (size_t)size, f)); fclose(f); // Try to read all headers and bodies. assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (0 == archive_read_open_memory(a, image, size)) { while(0 == archive_read_next_header(a, &ae)) { while (0 == archive_read_data_block(a, &blk, &blk_size, &blk_offset)) continue; } archive_read_close(a); } archive_read_free(a); // Just list headers, skip bodies. assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (0 == archive_read_open_memory(a, image, size)) { while(0 == archive_read_next_header(a, &ae)) { } archive_read_close(a); } archive_read_free(a); } free(image); free(rawimage); } }
/* * Read data from an archive entry, using a read(2)-style interface. * This is a convenience routine that just calls * archive_read_data_block and copies the results into the client * buffer, filling any gaps with zero bytes. Clients using this * API can be completely ignorant of sparse-file issues; sparse files * will simply be padded with nulls. * * DO NOT intermingle calls to this function and archive_read_data_block * to read a single entry body. */ ssize_t archive_read_data(struct archive *_a, void *buff, size_t s) { struct archive_read *a = (struct archive_read *)_a; char *dest; const void *read_buf; size_t bytes_read; size_t len; int r; bytes_read = 0; dest = (char *)buff; while (s > 0) { if (a->read_data_remaining == 0) { read_buf = a->read_data_block; r = archive_read_data_block(&a->archive, &read_buf, &a->read_data_remaining, &a->read_data_offset); a->read_data_block = read_buf; if (r == ARCHIVE_EOF) return (bytes_read); /* * Error codes are all negative, so the status * return here cannot be confused with a valid * byte count. (ARCHIVE_OK is zero.) */ if (r < ARCHIVE_OK) return (r); } if (a->read_data_offset < a->read_data_output_offset) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Encountered out-of-order sparse blocks"); return (ARCHIVE_RETRY); } /* Compute the amount of zero padding needed. */ if (a->read_data_output_offset + (off_t)s < a->read_data_offset) { len = s; } else if (a->read_data_output_offset < a->read_data_offset) { len = a->read_data_offset - a->read_data_output_offset; } else len = 0; /* Add zeroes. */ memset(dest, 0, len); s -= len; a->read_data_output_offset += len; dest += len; bytes_read += len; /* Copy data if there is any space left. */ if (s > 0) { len = a->read_data_remaining; if (len > s) len = s; memcpy(dest, a->read_data_block, len); s -= len; a->read_data_block += len; a->read_data_remaining -= len; a->read_data_output_offset += len; a->read_data_offset += len; dest += len; bytes_read += len; } } return (bytes_read); }
/* * Verify our ability to read sample files created by Solaris pax for * a sparse file. */ static void test_compat_solaris_pax_sparse_1(void) { char name[] = "test_compat_solaris_pax_sparse_1.pax.Z"; struct archive_entry *ae; struct archive *a; int64_t offset, length; const void *buff; size_t bytes_read; char data[1024*8]; int r; assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); extract_reference_file(name); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240)); /* Read first entry. */ assertEqualIntA(a, ARCHIVE_OK, r = archive_read_next_header(a, &ae)); if (r != ARCHIVE_OK) { archive_read_free(a); return; } assertEqualString("hole", archive_entry_pathname(ae)); assertEqualInt(1310411683, archive_entry_mtime(ae)); assertEqualInt(101, archive_entry_uid(ae)); assertEqualString("cue", archive_entry_uname(ae)); assertEqualInt(10, archive_entry_gid(ae)); assertEqualString("staff", archive_entry_gname(ae)); assertEqualInt(0100644, archive_entry_mode(ae)); /* Verify the sparse information. */ failure("This sparse file should have tree data blocks"); assertEqualInt(3, archive_entry_sparse_reset(ae)); assertEqualInt(ARCHIVE_OK, archive_entry_sparse_next(ae, &offset, &length)); assertEqualInt(0, offset); assertEqualInt(131072, length); assertEqualInt(ARCHIVE_OK, archive_entry_sparse_next(ae, &offset, &length)); assertEqualInt(393216, offset); assertEqualInt(131072, length); assertEqualInt(ARCHIVE_OK, archive_entry_sparse_next(ae, &offset, &length)); assertEqualInt(786432, offset); assertEqualInt(32775, length); while (ARCHIVE_OK == archive_read_data_block(a, &buff, &bytes_read, &offset)) { failure("The data blocks should not include the hole"); assert((offset >= 0 && offset + bytes_read <= 131072) || (offset >= 393216 && offset + bytes_read <= 393216+131072) || (offset >= 786432 && offset + bytes_read <= 786432+32775)); if (offset == 0 && bytes_read >= 1024*8) { memset(data, 'a', sizeof(data)); failure("First data block should be 8K bytes of 'a'"); assertEqualMem(buff, data, sizeof(data)); } else if (offset + bytes_read == 819207 && bytes_read >= 7) { const char *last = buff; last += bytes_read - 7; memset(data, 'c', 7); failure("Last seven bytes should be all 'c'"); assertEqualMem(last, data, 7); } } /* 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_COMPRESS); assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE); assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
int main(int argc, char* argv[]){ struct archive* ar; struct archive_entry* aren; int arnum; if(argc < 3){ fprintf(stderr, "Usage: %s infile outfile\n", argv[0]); return 255; } #ifdef ENABLE_STAGE_1 puts("==> Stage 1: Listing"); ar = archive_read_new(); archive_read_support_filter_all(ar); archive_read_support_format_all(ar); arnum = archive_read_open_filename(ar, argv[1], 16384); if(arnum != ARCHIVE_OK){ fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], archive_error_string(ar)); return 1; } while(archive_read_next_header(ar, &aren) == ARCHIVE_OK){ const char *hardlink, *symlink; printf("%s format: %s, pathname: %s, size: %"PRId64", links: %d," "username: %s, uid: %d", argv[1], archive_format_name(ar), archive_entry_pathname(aren), archive_entry_size(aren), archive_entry_nlink(aren), archive_entry_uname(aren), archive_entry_uid(aren)); hardlink = archive_entry_hardlink(aren); symlink = archive_entry_symlink(aren); if(hardlink != NULL){ printf(", hardlink: %s", hardlink); } if(symlink != NULL){ printf(", symlink: %s", symlink); } putchar('\n'); } archive_read_close(ar); archive_read_free(ar); #endif #ifdef ENABLE_STAGE_2 puts("==> Stage 2: Displaying"); ar = archive_read_new(); archive_read_support_filter_all(ar); archive_read_support_format_all(ar); arnum = archive_read_open_filename(ar, argv[1], 16384); if(arnum != ARCHIVE_OK){ fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], archive_error_string(ar)); return 2; } while(archive_read_next_header(ar, &aren) == ARCHIVE_OK){ printf("<<< %s >>>\n", archive_entry_pathname(aren)); for(;;){ size_t size; off_t offset; const void* buffer; switch(archive_read_data_block(ar, &buffer, &size, &offset)){ case ARCHIVE_OK: puts(":: Block reading succeeded"); fwrite(buffer, size, 1, stdout); break; case ARCHIVE_WARN: puts(":: Block reading succeeded, warning exists"); fwrite(buffer, size, 1, stdout); break; case ARCHIVE_EOF: goto loop_outside; case ARCHIVE_RETRY: puts(":: Block reading failed, retrying"); break; case ARCHIVE_FATAL: puts(":: Fatal error! STOP!"); return 2; } } loop_outside: puts("@@ Extract OK @@"); } archive_read_close(ar); archive_read_free(ar); #endif #ifdef ENABLE_STAGE_3 puts("==> Stage 3: Extracting"); struct archive* arext; ar = archive_read_new(); archive_read_support_format_all(ar); archive_read_support_filter_all(ar); arext = archive_write_disk_new(); archive_write_disk_set_options(arext, ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR ); archive_write_disk_set_standard_lookup(arext); if(archive_read_open_filename(ar, argv[1], 16384)){ fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], archive_error_string(ar)); return 3; } while((arnum = archive_read_next_header(ar, &aren)) == ARCHIVE_OK){ int filesize, accsize; printf("<<< %s >>>\n", archive_entry_pathname(aren)); if(archive_write_header(arext, aren) != ARCHIVE_OK){ puts(":: Write header not OK ..."); }else if((filesize = archive_entry_size(aren)) > 0){ accsize = 0; for(;;){ size_t size; off_t offset; const void* buffer; arnum = archive_read_data_block(ar, &buffer, &size, &offset); if(arnum != ARCHIVE_OK){ break; } arnum = archive_write_data(arext, buffer, size); if(arnum >= 0){ accsize += arnum; printf(":: %d of %d bytes written\n", accsize, filesize); } } } if(archive_write_finish_entry(arext) != ARCHIVE_OK){ return 3; } } archive_read_close(ar); archive_read_free(ar); archive_write_close(arext); archive_write_free(arext); #endif return 0; }
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; }
static void verify_archive_file(const char *name, struct archive_contents *ac) { struct archive_entry *ae; int err; /* data, size, offset of next expected block. */ struct contents expect; /* data, size, offset of block read from archive. */ struct contents actual; const void *p; struct archive *a; extract_reference_file(name); assert((a = archive_read_new()) != NULL); assert(0 == archive_read_support_filter_all(a)); assert(0 == archive_read_support_format_tar(a)); failure("Can't open %s", name); assert(0 == archive_read_open_filename(a, name, 3)); while (ac->filename != NULL) { struct contents *cts = ac->contents; if (!assertEqualIntA(a, 0, archive_read_next_header(a, &ae))) { assertEqualInt(ARCHIVE_OK, archive_read_free(a)); return; } failure("Name mismatch in archive %s", name); assertEqualString(ac->filename, archive_entry_pathname(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); expect = *cts++; while (0 == (err = archive_read_data_block(a, &p, &actual.s, &actual.o))) { actual.d = p; while (actual.s > 0) { char c = *actual.d; if(actual.o < expect.o) { /* * Any byte before the expected * data must be NULL. */ failure("%s: pad at offset %d " "should be zero", name, actual.o); assertEqualInt(c, 0); } else if (actual.o == expect.o) { /* * Data at matching offsets must match. */ assertEqualInt(c, *expect.d); expect.d++; expect.o++; expect.s--; /* End of expected? step to next expected. */ if (expect.s <= 0) expect = *cts++; } else { /* * We found data beyond that expected. */ failure("%s: Unexpected trailing data", name); assert(actual.o <= expect.o); archive_read_free(a); return; } actual.d++; actual.o++; actual.s--; } } failure("%s: should be end of entry", name); assertEqualIntA(a, err, ARCHIVE_EOF); failure("%s: Size returned at EOF must be zero", name); assertEqualInt((int)actual.s, 0); failure("%s: Offset of final empty chunk must be same as file size", name); assertEqualInt(actual.o, expect.o); /* Step to next file description. */ ++ac; } err = archive_read_next_header(a, &ae); assertEqualIntA(a, ARCHIVE_EOF, err); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
/* * The reference file for this has been manually tweaked so that: * * file2 has length-at-end but file1 does not * * file2 has an invalid CRC */ static void verify_basic(struct archive *a, int seek_checks) { struct archive_entry *ae; char *buff[128]; const void *pv; size_t s; int64_t o; assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("dir/", archive_entry_pathname(ae)); assertEqualInt(1179604249, archive_entry_mtime(ae)); assertEqualInt(0, archive_entry_size(ae)); if (seek_checks) assertEqualInt(AE_IFDIR | 0755, archive_entry_mode(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); assertEqualIntA(a, ARCHIVE_EOF, archive_read_data_block(a, &pv, &s, &o)); assertEqualInt((int)s, 0); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("file1", archive_entry_pathname(ae)); assertEqualInt(1179604289, archive_entry_mtime(ae)); if (seek_checks) assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae)); assertEqualInt(18, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); failure("archive_read_data() returns number of bytes read"); if (archive_zlib_version() != NULL) { assertEqualInt(18, archive_read_data(a, buff, 19)); assertEqualMem(buff, "hello\nhello\nhello\n", 18); } else { assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, 19)); assertEqualString(archive_error_string(a), "Unsupported ZIP compression method (deflation)"); assert(archive_errno(a) != 0); } assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("file2", archive_entry_pathname(ae)); assertEqualInt(1179605932, archive_entry_mtime(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); if (seek_checks) { assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae)); } assert(archive_entry_size_is_set(ae)); assertEqualInt(18, archive_entry_size(ae)); if (archive_zlib_version() != NULL) { failure("file2 has a bad CRC, so read should fail and not change buff"); memset(buff, 'a', 19); assertEqualInt(ARCHIVE_WARN, archive_read_data(a, buff, 19)); assertEqualMem(buff, "aaaaaaaaaaaaaaaaaaa", 19); } else { assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, 19)); assertEqualString(archive_error_string(a), "Unsupported ZIP compression method (deflation)"); assert(archive_errno(a) != 0); } assertEqualInt(ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify the number of files read. */ failure("the archive file has three files"); assertEqualInt(3, archive_file_count(a)); assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_ZIP, archive_format(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
static int add_pattern_from_file(struct archive_match *a, struct match_list *mlist, int mbs, const void *pathname, int nullSeparator) { struct archive *ar; struct archive_entry *ae; struct archive_string as; const void *buff; size_t size; int64_t offset; int r; ar = archive_read_new(); if (ar == NULL) { archive_set_error(&(a->archive), ENOMEM, "No memory"); return (ARCHIVE_FATAL); } r = archive_read_support_format_raw(ar); r = archive_read_support_format_empty(ar); if (r != ARCHIVE_OK) { archive_copy_error(&(a->archive), ar); archive_read_free(ar); return (r); } if (mbs) r = archive_read_open_filename(ar, pathname, 512*20); else r = archive_read_open_filename_w(ar, pathname, 512*20); if (r != ARCHIVE_OK) { archive_copy_error(&(a->archive), ar); archive_read_free(ar); return (r); } r = archive_read_next_header(ar, &ae); if (r != ARCHIVE_OK) { archive_read_free(ar); if (r == ARCHIVE_EOF) { return (ARCHIVE_OK); } else { archive_copy_error(&(a->archive), ar); return (r); } } archive_string_init(&as); while ((r = archive_read_data_block(ar, &buff, &size, &offset)) == ARCHIVE_OK) { const char *b = (const char *)buff; while (size) { const char *s = (const char *)b; size_t length = 0; int found_separator = 0; while (length < size) { if (nullSeparator) { if (*b == '\0') { found_separator = 1; break; } } else { if (*b == 0x0d || *b == 0x0a) { found_separator = 1; break; } } b++; length++; } if (!found_separator) { archive_strncat(&as, s, length); /* Read next data block. */ break; } b++; size -= length + 1; archive_strncat(&as, s, length); /* If the line is not empty, add the pattern. */ if (archive_strlen(&as) > 0) { /* Add pattern. */ r = add_pattern_mbs(a, mlist, as.s); if (r != ARCHIVE_OK) { archive_read_free(ar); archive_string_free(&as); return (r); } archive_string_empty(&as); } } } /* If an error occurred, report it immediately. */ if (r < ARCHIVE_OK) { archive_copy_error(&(a->archive), ar); archive_read_free(ar); archive_string_free(&as); return (r); } /* If the line is not empty, add the pattern. */ if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) { /* Add pattern. */ r = add_pattern_mbs(a, mlist, as.s); if (r != ARCHIVE_OK) { archive_read_free(ar); archive_string_free(&as); return (r); } } archive_read_free(ar); archive_string_free(&as); return (ARCHIVE_OK); }
static int arxive_read_block(arc_handle_t ar, const void** chunkData, size_t* chunkSize, off_t* chunkOffset) { return archive_read_data_block(ar, chunkData, chunkSize, chunkOffset); }
//******************************************************************************************************** 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); } }
/* * Sparse test with directory traversals. */ static void verify_sparse_file(struct archive *a, const char *path, const struct sparse *sparse, int expected_holes) { struct archive_entry *ae; const void *buff; size_t bytes_read; int64_t offset, expected_offset, last_offset; int holes_seen = 0; create_sparse_file(path, sparse); assert((ae = archive_entry_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, path)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); expected_offset = 0; last_offset = 0; while (ARCHIVE_OK == archive_read_data_block(a, &buff, &bytes_read, &offset)) { const char *start = buff; #if DEBUG fprintf(stderr, "%s: bytes_read=%d offset=%d\n", path, (int)bytes_read, (int)offset); #endif if (offset > last_offset) { ++holes_seen; } /* Blocks entirely before the data we just read. */ while (expected_offset + (int64_t)sparse->size < offset) { #if DEBUG fprintf(stderr, " skipping expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size); #endif /* Must be holes. */ assert(sparse->type == HOLE); expected_offset += sparse->size; ++sparse; } /* Block that overlaps beginning of data */ if (expected_offset < offset && expected_offset + (int64_t)sparse->size <= offset + (int64_t)bytes_read) { const char *end = (const char *)buff + (expected_offset - offset) + (size_t)sparse->size; #if DEBUG fprintf(stderr, " overlapping hole expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size); #endif /* Must be a hole, overlap must be filled with '\0' */ if (assert(sparse->type == HOLE)) { assertMemoryFilledWith(start, end - start, '\0'); } start = end; expected_offset += sparse->size; ++sparse; } /* Blocks completely contained in data we just read. */ while (expected_offset + (int64_t)sparse->size <= offset + (int64_t)bytes_read) { const char *end = (const char *)buff + (expected_offset - offset) + (size_t)sparse->size; if (sparse->type == HOLE) { #if DEBUG fprintf(stderr, " contained hole expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size); #endif /* verify data corresponding to hole is '\0' */ if (end > (const char *)buff + bytes_read) { end = (const char *)buff + bytes_read; } assertMemoryFilledWith(start, end - start, '\0'); start = end; expected_offset += sparse->size; ++sparse; } else if (sparse->type == DATA) { #if DEBUG fprintf(stderr, " contained data expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size); #endif /* verify data corresponding to hole is ' ' */ if (assert(expected_offset + sparse->size <= offset + bytes_read)) { assert(start == (const char *)buff + (size_t)(expected_offset - offset)); assertMemoryFilledWith(start, end - start, ' '); } start = end; expected_offset += sparse->size; ++sparse; } else { break; } } /* Block that overlaps end of data */ if (expected_offset < offset + (int64_t)bytes_read) { const char *end = (const char *)buff + bytes_read; #if DEBUG fprintf(stderr, " trailing overlap expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size); #endif /* Must be a hole, overlap must be filled with '\0' */ if (assert(sparse->type == HOLE)) { assertMemoryFilledWith(start, end - start, '\0'); } } last_offset = offset + bytes_read; } /* Count a hole at EOF? */ if (last_offset < archive_entry_size(ae)) { ++holes_seen; } /* Verify blocks after last read */ while (sparse->type == HOLE) { expected_offset += sparse->size; ++sparse; } assert(sparse->type == END); assertEqualInt(expected_offset, archive_entry_size(ae)); failure(path); assertEqualInt(holes_seen, expected_holes); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); archive_entry_free(ae); }