static void create_reg_file3(struct archive_entry *ae, const char *msg) { static const char data[]="abcdefghijklmnopqrstuvwxyz"; struct archive *ad; struct stat st; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); failure("%s", msg); /* Set the size smaller than the data and verify the truncation. */ archive_entry_set_size(ae, 5); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); assertEqualInt(5, 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 entry on disk. */ assert(0 == stat(archive_entry_pathname(ae), &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); #if !defined(_WIN32) || defined(__CYGWIN__) assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK)); #endif assertEqualInt(st.st_size, 5); }
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; };
static void create_reg_file4(struct archive_entry *ae, const char *msg) { static const char data[]="abcdefghijklmnopqrstuvwxyz"; struct archive *ad; struct stat st; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); /* Leave the size unset. The data should not be truncated. */ assertEqualIntA(ad, 0, archive_write_header(ad, ae)); assertEqualInt(ARCHIVE_OK, archive_write_data_block(ad, data, sizeof(data), 0)); 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 entry on disk. */ assert(0 == stat(archive_entry_pathname(ae), &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); #if !defined(_WIN32) || defined(__CYGWIN__) assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK)); #endif failure(msg); assertEqualInt(st.st_size, sizeof(data)); }
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); }
static void create_reg_file2(struct archive_entry *ae, const char *msg) { const int datasize = 100000; char *data; struct archive *ad; int i; data = malloc(datasize); for (i = 0; i < datasize; i++) data[i] = (char)(i % 256); /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); failure("%s", msg); /* * See above for an explanation why this next call * is necessary. */ archive_entry_set_size(ae, datasize); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); for (i = 0; i < datasize - 999; i += 1000) { assertEqualIntA(ad, ARCHIVE_OK, archive_write_data_block(ad, data + i, 1000, i)); } assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); assertEqualInt(0, archive_write_finish(ad)); /* Test the entries on disk. */ assertIsReg(archive_entry_pathname(ae), archive_entry_mode(ae) & 0777); assertFileSize(archive_entry_pathname(ae), i); assertFileContents(data, datasize, archive_entry_pathname(ae)); free(data); }
static struct extract * get_extract(struct archive_read *a) { /* If we haven't initialized, do it now. */ /* This also sets up a lot of global state. */ if (a->extract == NULL) { a->extract = (struct extract *)malloc(sizeof(*a->extract)); if (a->extract == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't extract"); return (NULL); } memset(a->extract, 0, sizeof(*a->extract)); a->extract->ad = archive_write_disk_new(); if (a->extract->ad == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't extract"); return (NULL); } if (archive_write_disk_set_standard_lookup(a->extract->ad)) { archive_set_error(&a->archive, ENOMEM, "Can't extract"); return (NULL); } a->cleanup_archive_extract = archive_read_extract_cleanup; } return (a->extract); }
static void create(struct archive_entry *ae, const char *msg) { struct archive *ad; struct stat st; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); failure("%s", msg); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); #if ARCHIVE_API_VERSION > 1 assertEqualInt(0, archive_write_finish(ad)); #else archive_write_finish(ad); #endif /* Test the entries on disk. */ assert(0 == stat(archive_entry_pathname(ae), &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); /* When verifying a dir, ignore the S_ISGID bit, as some systems set * that automatically. */ if (archive_entry_filetype(ae) == AE_IFDIR) st.st_mode &= ~S_ISGID; assertEqualInt(st.st_mode, archive_entry_mode(ae) & ~UMASK); }
/* * 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 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); }
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); }
void restraint_fetch_http (SoupURI *url, const gchar *base_path, ArchiveEntryCallback archive_entry_callback, FetchFinishCallback finish_callback, gpointer user_data) { g_return_if_fail(url != NULL); g_return_if_fail(base_path != NULL); FetchData *fetch_data = g_slice_new0(FetchData); fetch_data->archive_entry_callback = archive_entry_callback; fetch_data->finish_callback = finish_callback; fetch_data->user_data = user_data; fetch_data->url = url; fetch_data->base_path = base_path; GError *tmp_error = NULL; gint r; session = soup_session_new(); fetch_data->a = archive_read_new(); if (fetch_data->a == NULL) { g_set_error(&fetch_data->error, RESTRAINT_FETCH_LIBARCHIVE_ERROR, 0, "archive_read_new failed"); g_idle_add (archive_finish_callback, fetch_data); return; } fetch_data->ext = archive_write_disk_new(); if (fetch_data->ext == NULL) { g_set_error(&fetch_data->error, RESTRAINT_FETCH_LIBARCHIVE_ERROR, 0, "archive_write_disk_new failed"); g_idle_add (archive_finish_callback, fetch_data); return; } archive_read_support_filter_all(fetch_data->a); archive_read_support_format_all(fetch_data->a); gboolean open_succeeded = myopen(fetch_data, &tmp_error); if (!open_succeeded) { g_propagate_error(&fetch_data->error, tmp_error); g_idle_add (archive_finish_callback, fetch_data); return; } r = archive_read_open(fetch_data->a, fetch_data, NULL, myread, myclose); if (r != ARCHIVE_OK) { g_set_error(&fetch_data->error, RESTRAINT_FETCH_LIBARCHIVE_ERROR, r, "archive_read_open failed: %s", archive_error_string(fetch_data->a)); g_idle_add (archive_finish_callback, fetch_data); return; } g_idle_add (http_archive_read_callback, fetch_data); }
bool extract_archive(const std::string &filename, const std::string &target) { 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 false; } archive_entry *entry; int ret; std::string cwd = get_cwd(); if (cwd.empty()) { return false; } if (!set_up_input(in.get(), filename)) { return false; } set_up_output(out.get()); if (!mkdir_recursive(target, S_IRWXU | S_IRWXG | S_IRWXO)) { LOGE("%s: Failed to create directory: %s", target.c_str(), strerror(errno)); return false; } if (chdir(target.c_str()) < 0) { LOGE("%s: Failed to change to target directory: %s", target.c_str(), strerror(errno)); return false; } auto chdir_back = finally([&] { chdir(cwd.c_str()); }); while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) { if (libarchive_copy_header_and_data(in.get(), out.get(), entry) != ARCHIVE_OK) { return false; } } if (ret != ARCHIVE_EOF) { LOGE("Archive extraction ended without reaching EOF: %s", archive_error_string(in.get())); return false; } return true; }
bool extract_files2(const std::string &filename, const std::vector<extract_info> &files) { if (files.empty()) { return false; } 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 false; } archive_entry *entry; int ret; unsigned int count = 0; if (!set_up_input(in.get(), filename)) { return false; } set_up_output(out.get()); while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) { for (const extract_info &info : files) { if (info.from == archive_entry_pathname(entry)) { ++count; archive_entry_set_pathname(entry, info.to.c_str()); if (libarchive_copy_header_and_data(in.get(), out.get(), entry) != ARCHIVE_OK) { return false; } archive_entry_set_pathname(entry, info.from.c_str()); } } } if (ret != ARCHIVE_EOF) { LOGE("Archive extraction ended without reaching EOF: %s", archive_error_string(in.get())); return false; } if (count != files.size()) { LOGE("Not all specified files were extracted"); return false; } return true; }
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); }
// 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); }
static void create_reg_file2(struct archive_entry *ae, const char *msg) { const int datasize = 100000; char *data; char *compare; struct archive *ad; struct stat st; int i, fd; data = malloc(datasize); for (i = 0; i < datasize; i++) data[i] = (char)(i % 256); /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); failure("%s", msg); /* * See above for an explanation why this next call * is necessary. */ archive_entry_set_size(ae, datasize); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); for (i = 0; i < datasize - 999; i += 1000) { assertEqualIntA(ad, ARCHIVE_OK, archive_write_data_block(ad, data + i, 1000, i)); } assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); #if ARCHIVE_API_VERSION > 1 assertEqualInt(0, archive_write_finish(ad)); #else archive_write_finish(ad); #endif /* Test the entries on disk. */ assert(0 == stat(archive_entry_pathname(ae), &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK)); assertEqualInt(st.st_size, i); compare = malloc(datasize); fd = open(archive_entry_pathname(ae), O_RDONLY); assertEqualInt(datasize, read(fd, compare, datasize)); close(fd); assert(memcmp(compare, data, datasize) == 0); free(compare); free(data); }
static void extract (int fd) { struct archive *a; struct archive *ext; struct archive_entry *entry; int r; a = archive_read_new (); ext = archive_write_disk_new (); archive_read_support_format_tar (a); archive_read_support_filter_xz (a); archive_read_support_filter_gzip (a); if ((r = archive_read_open_fd (a, fd, 16*1024))) die_with_libarchive (a, "archive_read_open_fd: %s"); while (1) { r = archive_read_next_header (a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) die_with_libarchive (a, "archive_read_next_header: %s"); if (!should_extract (entry)) continue; r = archive_write_header (ext, entry); if (r != ARCHIVE_OK) die_with_libarchive (ext, "archive_write_header: %s"); else { copy_archive (a, ext); r = archive_write_finish_entry (ext); if (r != ARCHIVE_OK) die_with_libarchive (ext, "archive_write_finish_entry: %s"); } } archive_read_close (a); archive_read_free (a); archive_write_close (ext); archive_write_free (ext); }
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 create_reg_file(struct archive_entry *ae, const char *msg) { static const char data[]="abcdefghijklmnopqrstuvwxyz"; struct archive *ad; struct stat st; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); 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)); 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_API_VERSION > 1 assertEqualInt(0, archive_write_finish(ad)); #else archive_write_finish(ad); #endif /* Test the entries on disk. */ assert(0 == stat(archive_entry_pathname(ae), &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK)); assertEqualInt(st.st_size, sizeof(data)); }
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 void create(struct archive_entry *ae, const char *msg) { struct archive *ad; struct stat st; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); failure("%s", msg); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); #if ARCHIVE_API_VERSION > 1 assertEqualInt(0, archive_write_finish(ad)); #else archive_write_finish(ad); #endif /* Test the entries on disk. */ assert(0 == stat(archive_entry_pathname(ae), &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); assert(st.st_mode == (archive_entry_mode(ae) & ~UMASK)); }
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)); }
static void create_reg_file(struct archive_entry *ae, const char *msg) { static const char data[]="abcdefghijklmnopqrstuvwxyz"; struct archive *ad; struct stat st; /* Write the entry to disk. */ assert((ad = archive_write_disk_new()) != NULL); failure("%s", msg); 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_API_VERSION > 1 assertEqualInt(0, archive_write_finish(ad)); #else archive_write_finish(ad); #endif /* Test the entries on disk. */ assert(0 == stat(archive_entry_pathname(ae), &st)); failure("st.st_mode=%o archive_entry_mode(ae)=%o", st.st_mode, archive_entry_mode(ae)); assertEqualInt(st.st_mode, (archive_entry_mode(ae) & ~UMASK)); 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. std::string block_dev(_recovery_block_dev); mbp::BootImage bi; mbp::CpioFile innerCpio; const unsigned char *ramdisk_data; std::size_t ramdisk_size; bool using_boot = false; // Check if the device has a combined boot/recovery partition. If the // FOTAKernel partition is listed, it will be used instead of the combined // ramdisk from the boot image bool combined = mb_device_flags(_device) & FLAG_HAS_COMBINED_BOOT_AND_RECOVERY; if (combined && block_dev.empty()) { block_dev = _boot_block_dev; using_boot = true; } if (block_dev.empty()) { display_msg("Could not determine the recovery block device"); return ProceedState::Fail; } if (!bi.loadFile(block_dev)) { display_msg("Failed to load recovery partition image"); return ProceedState::Fail; } // Load ramdisk bi.ramdiskImageC(&ramdisk_data, &ramdisk_size); if (using_boot) { if (!innerCpio.load(ramdisk_data, ramdisk_size)) { display_msg("Failed to load ramdisk from combined boot image"); return ProceedState::Fail; } if (!innerCpio.contentsC("sbin/ramdisk-recovery.cpio", &ramdisk_data, &ramdisk_size)) { display_msg("Could not find recovery ramdisk in combined boot image"); return ProceedState::Fail; } } autoclose::archive in(archive_read_new(), archive_read_free); autoclose::archive out(archive_write_disk_new(), archive_write_free); if (!in || !out) { LOGE("Out of memory"); return ProceedState::Fail; } archive_entry *entry; // Set up input archive_read_support_filter_gzip(in.get()); archive_read_support_filter_lzop(in.get()); archive_read_support_filter_lz4(in.get()); archive_read_support_filter_lzma(in.get()); archive_read_support_filter_xz(in.get()); archive_read_support_format_cpio(in.get()); int ret = archive_read_open_memory(in.get(), const_cast<unsigned char *>(ramdisk_data), ramdisk_size); if (ret != ARCHIVE_OK) { LOGW("Failed to open recovery ramdisk: %s", archive_error_string(in.get())); return ProceedState::Fail; } // Set up output archive_write_disk_set_options(out.get(), ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_SECURE_NODOTDOT | ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK | ARCHIVE_EXTRACT_XATTR); while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) { std::string path = archive_entry_pathname(entry); if (path == "default.prop") { path = "default.recovery.prop"; } else if (!util::starts_with(path, "sbin/")) { continue; } LOGE("Copying from recovery: %s", path.c_str()); archive_entry_set_pathname(entry, in_chroot(path).c_str()); if (util::libarchive_copy_header_and_data( in.get(), out.get(), entry) != ARCHIVE_OK) { return ProceedState::Fail; } archive_entry_set_pathname(entry, path.c_str()); } if (ret != ARCHIVE_EOF) { LOGE("Archive extraction ended without reaching EOF: %s", archive_error_string(in.get())); return ProceedState::Fail; } // Create fake /etc/fstab file to please installers that read the file std::string etc_fstab(in_chroot("/etc/fstab")); if (access(etc_fstab.c_str(), R_OK) < 0 && errno == ENOENT) { autoclose::file fp(autoclose::fopen(etc_fstab.c_str(), "w")); if (fp) { auto system_devs = mb_device_system_block_devs(_device); auto cache_devs = mb_device_cache_block_devs(_device); auto data_devs = mb_device_data_block_devs(_device); // Set block device if it's provided and non-empty const char *system_dev = system_devs && system_devs[0] && system_devs[0][0] ? system_devs[0] : "dummy"; const char *cache_dev = cache_devs && cache_devs[0] && cache_devs[0][0] ? cache_devs[0] : "dummy"; const char *data_dev = data_devs && data_devs[0] && data_devs[0][0] ? data_devs[0] : "dummy"; fprintf(fp.get(), "%s /system ext4 rw 0 0\n", system_dev); fprintf(fp.get(), "%s /cache ext4 rw 0 0\n", cache_dev); fprintf(fp.get(), "%s /data ext4 rw 0 0\n", data_dev); } } // Load recovery properties util::file_get_all_properties( in_chroot("/default.recovery.prop"), &_recovery_props); return ProceedState::Continue; }
Installer::ProceedState RomInstaller::on_checked_device() { // /sbin is not going to be populated with anything useful in a normal boot // image. We can almost guarantee that a recovery image is going to be // installed though, so we'll open the recovery partition with libmbp and // extract its /sbin with libarchive into the chroot's /sbin. mbp::BootImage bi; if (!bi.loadFile(_recovery_block_dev)) { display_msg("Failed to load recovery partition image"); return ProceedState::Fail; } const unsigned char *ramdisk_data; std::size_t ramdisk_size; bi.ramdiskImageC(&ramdisk_data, &ramdisk_size); autoclose::archive in(archive_read_new(), archive_read_free); autoclose::archive out(archive_write_disk_new(), archive_write_free); if (!in | !out) { LOGE("Out of memory"); return ProceedState::Fail; } archive_entry *entry; // Set up input archive_read_support_filter_gzip(in.get()); archive_read_support_filter_lzop(in.get()); archive_read_support_filter_lz4(in.get()); archive_read_support_filter_lzma(in.get()); archive_read_support_format_cpio(in.get()); int ret = archive_read_open_memory(in.get(), const_cast<unsigned char *>(ramdisk_data), ramdisk_size); if (ret != ARCHIVE_OK) { LOGW("Failed to open recovery ramdisk: %s", archive_error_string(in.get())); return ProceedState::Fail; } // Set up output archive_write_disk_set_options(out.get(), ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_SECURE_NODOTDOT | ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK | ARCHIVE_EXTRACT_XATTR); while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) { std::string path = archive_entry_pathname(entry); if (!util::starts_with(path, "sbin/")) { continue; } LOGE("Copying from recovery: %s", path.c_str()); archive_entry_set_pathname(entry, (_chroot + "/" + path).c_str()); if (util::archive_copy_header_and_data(in.get(), out.get(), entry) != ARCHIVE_OK) { return ProceedState::Fail; } archive_entry_set_pathname(entry, path.c_str()); } if (ret != ARCHIVE_EOF) { LOGE("Archive extraction ended without reaching EOF: %s", archive_error_string(in.get())); return ProceedState::Fail; } return ProceedState::Continue; }