/* * Verify that test_read_extract correctly works with * Zip entries that use length-at-end. */ static void verify_extract_length_at_end(struct archive *a, int seek_checks) { struct archive_entry *ae; assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); assertEqualString("hello.txt", archive_entry_pathname(ae)); if (seek_checks) { assertEqualInt(AE_IFREG | 0644, archive_entry_mode(ae)); assert(archive_entry_size_is_set(ae)); assertEqualInt(6, archive_entry_size(ae)); } else { assert(!archive_entry_size_is_set(ae)); assertEqualInt(0, archive_entry_size(ae)); } if (archive_zlib_version() != NULL) { assertEqualIntA(a, ARCHIVE_OK, archive_read_extract(a, ae, 0)); assertFileContents("hello\x0A", 6, "hello.txt"); } else { assertEqualIntA(a, ARCHIVE_FAILED, archive_read_extract(a, ae, 0)); assertEqualString(archive_error_string(a), "Unsupported ZIP compression method (deflation)"); assert(archive_errno(a) != 0); } assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); }
static void verify_file0_stream(struct archive *a, int size_known) { struct archive_entry *ae; assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("-", archive_entry_pathname(ae)); assertEqualInt(AE_IFREG | 0664, archive_entry_mode(ae)); if (size_known) { // zip64b has the uncompressed size at the beginning, // plus CRC and compressed size using length-at-end. assert(archive_entry_size_is_set(ae)); assertEqualInt(6, archive_entry_size(ae)); } else { // zip64a does not have a size at the beginning at all. assert(!archive_entry_size_is_set(ae)); } #ifdef HAVE_ZLIB_H { char data[16]; assertEqualIntA(a, 6, archive_read_data(a, data, 16)); assertEqualMem(data, "file0\x0a", 6); } #endif assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); }
/** * A file with leading garbage (similar to an SFX file). */ static void test_compat_zip_4(void) { const char *refname = "test_compat_zip_4.zip"; struct archive_entry *ae; struct archive *a; void *p; size_t s; extract_reference_file(refname); p = slurpfile(&s, refname); /* SFX files require seek support. */ 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)); assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 18)); /* First entry. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("foo", archive_entry_pathname(ae)); assertEqualInt(4, archive_entry_size(ae)); assert(archive_entry_size_is_set(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(0412, archive_entry_perm(ae)); /* Second entry. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("bar", archive_entry_pathname(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(4, archive_entry_size(ae)); assert(archive_entry_size_is_set(ae)); assertEqualInt(0567, archive_entry_perm(ae)); /* Third entry. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("baz", archive_entry_pathname(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(4, archive_entry_size(ae)); assert(archive_entry_size_is_set(ae)); assertEqualInt(0644, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); /* Try reading without seek support and watch it fail. */ 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)); assertEqualIntA(a, ARCHIVE_FATAL, read_open_memory(a, p, s, 3)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); free(p); }
static int archive_write_newc_header(struct archive_write *a, struct archive_entry *entry) { const char *path; size_t len; if (archive_entry_filetype(entry) == 0) { archive_set_error(&a->archive, -1, "Filetype required"); return (ARCHIVE_FAILED); } if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 && errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathname"); return (ARCHIVE_FATAL); } if (len == 0 || path == NULL || path[0] == '\0') { archive_set_error(&a->archive, -1, "Pathname required"); return (ARCHIVE_FAILED); } if (archive_entry_hardlink(entry) == NULL && (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0)) { archive_set_error(&a->archive, -1, "Size required"); return (ARCHIVE_FAILED); } return write_header(a, entry); }
int archive_read_extract2(struct archive *_a, struct archive_entry *entry, struct archive *ad) { struct archive_read *a = (struct archive_read *)_a; int r, r2; /* Set up for this particular entry. */ if (a->skip_file_set) archive_write_disk_set_skip_file(ad, a->skip_file_dev, a->skip_file_ino); r = archive_write_header(ad, entry); if (r < ARCHIVE_WARN) r = ARCHIVE_WARN; if (r != ARCHIVE_OK) /* If _write_header failed, copy the error. */ archive_copy_error(&a->archive, ad); else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) /* Otherwise, pour data into the entry. */ r = copy_data(_a, ad); r2 = archive_write_finish_entry(ad); if (r2 < ARCHIVE_WARN) r2 = ARCHIVE_WARN; /* Use the first message. */ if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) archive_copy_error(&a->archive, ad); /* Use the worst error return. */ if (r2 < r) r = r2; return (r); }
static int Control( stream_extractor_t* p_extractor, int i_query, va_list args ) { private_sys_t* p_sys = p_extractor->p_sys; switch( i_query ) { case STREAM_CAN_FASTSEEK: *va_arg( args, bool* ) = false; break; case STREAM_CAN_SEEK: *va_arg( args, bool* ) = p_sys->b_seekable_source; break; case STREAM_GET_SIZE: if( p_sys->p_entry == NULL ) return VLC_EGENERIC; if( !archive_entry_size_is_set( p_sys->p_entry ) ) return VLC_EGENERIC; *va_arg( args, uint64_t* ) = archive_entry_size( p_sys->p_entry ); break; default: return vlc_stream_vaControl( p_extractor->source, i_query, args ); } return VLC_SUCCESS; }
static int reopen_archive(stream_t *s) { struct priv *p = s->priv; mp_archive_free(p->mpa); p->mpa = mp_archive_new(s->log, p->src, MP_ARCHIVE_FLAG_UNSAFE); if (!p->mpa) return STREAM_ERROR; // Follows the same logic as demux_libarchive.c. struct mp_archive *mpa = p->mpa; while (mp_archive_next_entry(mpa)) { if (strcmp(p->entry_name, mpa->entry_filename) == 0) { locale_t oldlocale = uselocale(mpa->locale); p->entry_size = -1; if (archive_entry_size_is_set(mpa->entry)) p->entry_size = archive_entry_size(mpa->entry); uselocale(oldlocale); return STREAM_OK; } } mp_archive_free(p->mpa); p->mpa = NULL; MP_ERR(s, "archive entry not found. '%s'\n", p->entry_name); return STREAM_ERROR; }
/* * Issue 185: Test a regression that got in between 2.6 and 2.7 that * broke extraction of Zip entries with length-at-end. */ static void test_compat_zip_3(void) { const char *refname = "test_compat_zip_3.zip"; struct archive_entry *ae; struct archive *a; extract_reference_file(refname); 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)); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* First entry. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("soapui-4.0.0/", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_size(ae)); assert(archive_entry_size_is_set(ae)); assertEqualInt(AE_IFDIR, archive_entry_filetype(ae)); /* Second entry. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("soapui-4.0.0/soapui-settings.xml", archive_entry_pathname(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(1030, archive_entry_size(ae)); assert(archive_entry_size_is_set(ae)); /* Extract under a different name. */ archive_entry_set_pathname(ae, "test_3.txt"); if(libz_enabled) { char *p; size_t s; assertEqualIntA(a, ARCHIVE_OK, archive_read_extract(a, ae, 0)); /* Verify the first 12 bytes actually got written to disk correctly. */ p = slurpfile(&s, "test_3.txt"); assertEqualInt(s, 1030); assertEqualMem(p, "<?xml versio", 12); free(p); } else { skipping("Skipping ZIP compression check, no libz support"); } assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); }
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); }
static int Seek( stream_extractor_t* p_extractor, uint64_t i_req ) { private_sys_t* p_sys = p_extractor->p_sys; if( !p_sys->p_entry || !p_sys->b_seekable_source ) return VLC_EGENERIC; if( archive_entry_size_is_set( p_sys->p_entry ) && (uint64_t)archive_entry_size( p_sys->p_entry ) <= i_req ) { p_sys->b_eof = true; return VLC_SUCCESS; } p_sys->b_eof = false; if( !p_sys->b_seekable_archive || p_sys->b_dead || archive_seek_data( p_sys->p_archive, i_req, SEEK_SET ) < 0 ) { msg_Dbg( p_extractor, "intrinsic seek failed: '%s' (falling back to dumb seek)", archive_error_string( p_sys->p_archive ) ); uint64_t i_skip = i_req - p_sys->i_offset; /* RECREATE LIBARCHIVE HANDLE IF WE ARE SEEKING BACKWARDS */ if( i_req < p_sys->i_offset ) { if( archive_extractor_reset( p_extractor ) ) { msg_Err( p_extractor, "unable to reset libarchive handle" ); return VLC_EGENERIC; } i_skip = i_req; } if( archive_skip_decompressed( p_extractor, i_skip ) ) msg_Dbg( p_extractor, "failed to skip to seek position" ); } p_sys->i_offset = i_req; return VLC_SUCCESS; }
static int ar_entry_size(lua_State *L) { struct archive_entry* self = *ar_entry_check(L, 1); int is_set; if ( NULL == self ) return 0; is_set = ( lua_gettop(L) == 2 ); if ( archive_entry_size_is_set(self) ) { lua_pushnumber(L, archive_entry_size(self)); } else { lua_pushnil(L); } if ( is_set ) { if ( lua_isnil(L, 2) ) { archive_entry_unset_size(self); } else { archive_entry_set_size(self, lua_tonumber(L, 2)); } } return 1; }
/* * 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("ZIP 1.0 (uncompressed)", archive_format_name(a)); 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("ZIP 2.0 (deflation)", archive_format_name(a)); 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("ZIP 2.0 (deflation)", archive_format_name(a)); 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)); assertEqualString("ZIP 2.0 (deflation)", archive_format_name(a)); /* 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)); }
/** * Issue 152: A file generated by a tool that doesn't really * believe in populating local file headers at all. This * is only readable with the seeking reader. */ static void test_compat_zip_5(void) { const char *refname = "test_compat_zip_5.zip"; struct archive_entry *ae; struct archive *a; void *p; size_t s; extract_reference_file(refname); p = slurpfile(&s, refname); /* Verify with seek support. * Everything works correctly here. */ 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)); assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 18)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Metadata/Job_PT.xml", archive_entry_pathname(ae)); assertEqualInt(3559, archive_entry_size(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Metadata/MXDC_Empty_PT.xml", archive_entry_pathname(ae)); assertEqualInt(456, archive_entry_size(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Metadata/Page1_Thumbnail.JPG", archive_entry_pathname(ae)); assertEqualInt(1495, archive_entry_size(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(0666, archive_entry_perm(ae)); /* TODO: Read some of the file data and verify it. The code to read uncompressed Zip entries with "file at end" semantics is tricky and should be verified more carefully. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Pages/_rels/1.fpage.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Pages/1.fpage", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Resources/Fonts/3DFDBC8B-4514-41F1-A808-DEA1C79BAC2B.odttf", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/_rels/FixedDocument.fdoc.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/FixedDocument.fdoc", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("_rels/FixedDocumentSequence.fdseq.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("FixedDocumentSequence.fdseq", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("_rels/.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("[Content_Types].xml", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); /* Try reading without seek support. */ 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)); assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 3)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Metadata/Job_PT.xml", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_size(ae)); assert(!archive_entry_size_is_set(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Metadata/MXDC_Empty_PT.xml", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_size(ae)); assert(!archive_entry_size_is_set(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Metadata/Page1_Thumbnail.JPG", archive_entry_pathname(ae)); assertEqualInt(0, archive_entry_size(ae)); assert(!archive_entry_size_is_set(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(0666, archive_entry_perm(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Pages/_rels/1.fpage.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Pages/1.fpage", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/Resources/Fonts/3DFDBC8B-4514-41F1-A808-DEA1C79BAC2B.odttf", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/_rels/FixedDocument.fdoc.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("Documents/1/FixedDocument.fdoc", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("_rels/FixedDocumentSequence.fdseq.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("FixedDocumentSequence.fdseq", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("_rels/.rels", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("[Content_Types].xml", archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); free(p); }
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_filter_all(a); archive_read_support_format_all(a); if (archive_read_open_filename(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 (archive_match_path_excluded(cpio->matching, 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(stderr, "%s\n", destpath); if (cpio->dot) fprintf(stderr, "."); 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_is_set(entry) || archive_entry_size(entry) > 0) { r = extract_data(a, ext); if (r != ARCHIVE_OK) cpio->return_value = 1; } } r = archive_read_close(a); if (cpio->dot) fprintf(stderr, "\n"); 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_filter_bytes(a, 0) + 511) / 512; fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } archive_read_free(a); archive_write_free(ext); exit(cpio->return_value); }
static int archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) { unsigned char local_header[32]; unsigned char local_extra[128]; struct zip *zip = a->format_data; unsigned char *e; unsigned char *cd_extra; size_t filename_length; const char *slink = NULL; size_t slink_size = 0; struct archive_string_conv *sconv = get_sconv(a, zip); int ret, ret2 = ARCHIVE_OK; int64_t size; mode_t type; int version_needed = 10; /* Ignore types of entries that we don't support. */ type = archive_entry_filetype(entry); if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Filetype not supported"); return ARCHIVE_FAILED; }; /* If we're not using Zip64, reject large files. */ if (zip->flags & ZIP_FLAG_AVOID_ZIP64) { /* Reject entries over 4GB. */ if (archive_entry_size_is_set(entry) && (archive_entry_size(entry) > 0xffffffff)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Files > 4GB require Zip64 extensions"); return ARCHIVE_FAILED; } /* Reject entries if archive is > 4GB. */ if (zip->written_bytes > 0xffffffff) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Archives > 4GB require Zip64 extensions"); return ARCHIVE_FAILED; } } /* Only regular files can have size > 0. */ if (type != AE_IFREG) archive_entry_set_size(entry, 0); /* Reset information from last entry. */ zip->entry_offset = zip->written_bytes; zip->entry_uncompressed_limit = INT64_MAX; zip->entry_compressed_size = 0; zip->entry_uncompressed_size = 0; zip->entry_compressed_written = 0; zip->entry_uncompressed_written = 0; zip->entry_flags = 0; zip->entry_uses_zip64 = 0; zip->entry_crc32 = zip->crc32func(0, NULL, 0); if (zip->entry != NULL) { archive_entry_free(zip->entry); zip->entry = NULL; } #if defined(_WIN32) && !defined(__CYGWIN__) /* Make sure the path separators in pahtname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ zip->entry = __la_win_entry_in_posix_pathseparator(entry); if (zip->entry == entry) zip->entry = archive_entry_clone(entry); #else zip->entry = archive_entry_clone(entry); #endif if (zip->entry == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate zip header data"); return (ARCHIVE_FATAL); } if (sconv != NULL) { const char *p; size_t len; if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathname"); return (ARCHIVE_FATAL); } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't translate Pathname '%s' to %s", archive_entry_pathname(entry), archive_string_conversion_charset_name(sconv)); ret2 = ARCHIVE_WARN; } if (len > 0) archive_entry_set_pathname(zip->entry, p); /* * There is no standard for symlink handling; we convert * it using the same character-set translation that we use * for filename. */ if (type == AE_IFLNK) { if (archive_entry_symlink_l(entry, &p, &len, sconv)) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory " " for Symlink"); return (ARCHIVE_FATAL); } /* No error if we can't convert. */ } else if (len > 0) archive_entry_set_symlink(zip->entry, p); } } /* If filename isn't ASCII and we can use UTF-8, set the UTF-8 flag. */ if (!is_all_ascii(archive_entry_pathname(zip->entry))) { if (zip->opt_sconv != NULL) { if (strcmp(archive_string_conversion_charset_name( zip->opt_sconv), "UTF-8") == 0) zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME; #if HAVE_NL_LANGINFO } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) { zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME; #endif } } filename_length = path_length(zip->entry); /* Determine appropriate compression and size for this entry. */ if (type == AE_IFLNK) { slink = archive_entry_symlink(zip->entry); if (slink != NULL) slink_size = strlen(slink); else slink_size = 0; zip->entry_uncompressed_limit = slink_size; zip->entry_compressed_size = slink_size; zip->entry_uncompressed_size = slink_size; zip->entry_crc32 = zip->crc32func(zip->entry_crc32, (const unsigned char *)slink, slink_size); zip->entry_compression = COMPRESSION_STORE; version_needed = 20; } else if (type != AE_IFREG) { zip->entry_compression = COMPRESSION_STORE; zip->entry_uncompressed_limit = 0; size = 0; version_needed = 20; } else if (archive_entry_size_is_set(zip->entry)) { size = archive_entry_size(zip->entry); zip->entry_uncompressed_limit = size; zip->entry_compression = zip->requested_compression; if (zip->entry_compression == COMPRESSION_UNSPECIFIED) { zip->entry_compression = COMPRESSION_DEFAULT; } if (zip->entry_compression == COMPRESSION_STORE) { zip->entry_compressed_size = size; zip->entry_uncompressed_size = size; version_needed = 10; } else { zip->entry_uncompressed_size = size; version_needed = 20; } if ((zip->flags & ZIP_FLAG_FORCE_ZIP64) /* User asked. */ || (zip->entry_uncompressed_size > ARCHIVE_LITERAL_LL(0xffffffff))) { /* Large entry. */ zip->entry_uses_zip64 = 1; version_needed = 45; } /* We may know the size, but never the CRC. */ zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END; } else { /* Prefer deflate if it's available, because deflate * has a clear end-of-data marker that makes * length-at-end more reliable. */ zip->entry_compression = COMPRESSION_DEFAULT; zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END; if ((zip->flags & ZIP_FLAG_AVOID_ZIP64) == 0) { zip->entry_uses_zip64 = 1; version_needed = 45; } else if (zip->entry_compression == COMPRESSION_STORE) { version_needed = 10; } else { version_needed = 20; } } /* Format the local header. */ memset(local_header, 0, sizeof(local_header)); memcpy(local_header, "PK\003\004", 4); archive_le16enc(local_header + 4, version_needed); archive_le16enc(local_header + 6, zip->entry_flags); archive_le16enc(local_header + 8, zip->entry_compression); archive_le32enc(local_header + 10, dos_time(archive_entry_mtime(zip->entry))); archive_le32enc(local_header + 14, zip->entry_crc32); if (zip->entry_uses_zip64) { /* Zip64 data in the local header "must" include both * compressed and uncompressed sizes AND those fields * are included only if these are 0xffffffff; * THEREFORE these must be set this way, even if we * know one of them is smaller. */ archive_le32enc(local_header + 18, ARCHIVE_LITERAL_LL(0xffffffff)); archive_le32enc(local_header + 22, ARCHIVE_LITERAL_LL(0xffffffff)); } else { archive_le32enc(local_header + 18, zip->entry_compressed_size); archive_le32enc(local_header + 22, zip->entry_uncompressed_size); } archive_le16enc(local_header + 26, filename_length); /* Format as much of central directory file header as we can: */ zip->file_header = cd_alloc(zip, 46); /* If (zip->file_header == NULL) XXXX */ ++zip->central_directory_entries; memset(zip->file_header, 0, 46); memcpy(zip->file_header, "PK\001\002", 4); /* "Made by PKZip 2.0 on Unix." */ archive_le16enc(zip->file_header + 4, 3 * 256 + version_needed); archive_le16enc(zip->file_header + 6, version_needed); archive_le16enc(zip->file_header + 8, zip->entry_flags); archive_le16enc(zip->file_header + 10, zip->entry_compression); archive_le32enc(zip->file_header + 12, dos_time(archive_entry_mtime(zip->entry))); archive_le16enc(zip->file_header + 28, filename_length); /* Following Info-Zip, store mode in the "external attributes" field. */ archive_le32enc(zip->file_header + 38, ((uint32_t)archive_entry_mode(zip->entry)) << 16); e = cd_alloc(zip, filename_length); /* If (e == NULL) XXXX */ copy_path(zip->entry, e); /* Format extra data. */ memset(local_extra, 0, sizeof(local_extra)); e = local_extra; /* First, extra blocks that are the same between * the local file header and the central directory. * We format them once and then duplicate them. */ /* UT timestamp, length depends on what timestamps are set. */ memcpy(e, "UT", 2); archive_le16enc(e + 2, 1 + (archive_entry_mtime_is_set(entry) ? 4 : 0) + (archive_entry_atime_is_set(entry) ? 4 : 0) + (archive_entry_ctime_is_set(entry) ? 4 : 0)); e += 4; *e++ = (archive_entry_mtime_is_set(entry) ? 1 : 0) | (archive_entry_atime_is_set(entry) ? 2 : 0) | (archive_entry_ctime_is_set(entry) ? 4 : 0); if (archive_entry_mtime_is_set(entry)) { archive_le32enc(e, (uint32_t)archive_entry_mtime(entry)); e += 4; } if (archive_entry_atime_is_set(entry)) { archive_le32enc(e, (uint32_t)archive_entry_atime(entry)); e += 4; } if (archive_entry_ctime_is_set(entry)) { archive_le32enc(e, (uint32_t)archive_entry_ctime(entry)); e += 4; } /* ux Unix extra data, length 11, version 1 */ /* TODO: If uid < 64k, use 2 bytes, ditto for gid. */ memcpy(e, "ux\013\000\001", 5); e += 5; *e++ = 4; /* Length of following UID */ archive_le32enc(e, (uint32_t)archive_entry_uid(entry)); e += 4; *e++ = 4; /* Length of following GID */ archive_le32enc(e, (uint32_t)archive_entry_gid(entry)); e += 4; /* Copy UT and ux into central directory as well. */ zip->file_header_extra_offset = zip->central_directory_bytes; cd_extra = cd_alloc(zip, e - local_extra); memcpy(cd_extra, local_extra, e - local_extra); /* * Following extra blocks vary between local header and * central directory. These are the local header versions. * Central directory versions get formatted in * archive_write_zip_finish_entry() below. */ /* "[Zip64 entry] in the local header MUST include BOTH * original [uncompressed] and compressed size fields." */ if (zip->entry_uses_zip64) { unsigned char *zip64_start = e; memcpy(e, "\001\000\020\000", 4); e += 4; archive_le64enc(e, zip->entry_uncompressed_size); e += 8; archive_le64enc(e, zip->entry_compressed_size); e += 8; archive_le16enc(zip64_start + 2, e - (zip64_start + 4)); } if (zip->flags & ZIP_FLAG_EXPERIMENT_EL) { /* Experimental 'el' extension to improve streaming. */ unsigned char *external_info = e; int included = 7; memcpy(e, "el\000\000", 4); // 0x6c65 + 2-byte length e += 4; e[0] = included; /* bitmap of included fields */ e += 1; if (included & 1) { archive_le16enc(e, /* "Version created by" */ 3 * 256 + version_needed); e += 2; } if (included & 2) { archive_le16enc(e, 0); /* internal file attributes */ e += 2; } if (included & 4) { archive_le32enc(e, /* external file attributes */ ((uint32_t)archive_entry_mode(zip->entry)) << 16); e += 4; } if (included & 8) { // Libarchive does not currently support file comments. } archive_le16enc(external_info + 2, e - (external_info + 4)); } /* Update local header with size of extra data and write it all out: */ archive_le16enc(local_header + 28, e - local_extra); ret = __archive_write_output(a, local_header, 30); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += 30; ret = write_path(zip->entry, a); if (ret <= ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += ret; ret = __archive_write_output(a, local_extra, e - local_extra); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += e - local_extra; /* For symlinks, write the body now. */ if (slink != NULL) { ret = __archive_write_output(a, slink, slink_size); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->entry_compressed_written += slink_size; zip->entry_uncompressed_written += slink_size; zip->written_bytes += slink_size; } #ifdef HAVE_ZLIB_H if (zip->entry_compression == COMPRESSION_DEFLATE) { zip->stream.zalloc = Z_NULL; zip->stream.zfree = Z_NULL; zip->stream.opaque = Z_NULL; zip->stream.next_out = zip->buf; zip->stream.avail_out = (uInt)zip->len_buf; if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { archive_set_error(&a->archive, ENOMEM, "Can't init deflate compressor"); return (ARCHIVE_FATAL); } } #endif return (ret2); }