void write_archive(const char *outname, const char **filename) { struct archive *a; struct archive_entry *entry; struct stat st; char buff[8192]; int len; int fd; a = archive_write_new(); archive_write_set_compression_gzip(a); archive_write_set_format_pax_restricted(a); // Note 1 archive_write_open_filename(a, outname, 10240); while (*filename) { stat(*filename, &st); entry = archive_entry_new(); // Note 2 archive_entry_set_pathname(entry, *filename); archive_entry_set_size(entry, st.st_size); // Note 3 archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_perm(entry, 0644); archive_write_header(a, entry); fd = open(*filename, O_RDONLY); len = read(fd, buff, sizeof(buff)); while ( len > 0 ) { archive_write_data(a, buff, len); len = read(fd, buff, sizeof(buff)); } close(fd); archive_entry_free(entry); filename++; } archive_write_close(a); // Note 4 archive_write_free(a); // Note 5 }
void archive_create(){ struct stat st; g_archive = archive_write_new(); archive_write_add_filter_gzip(g_archive); archive_write_set_format_pax_restricted(g_archive); // Note 1 }
void Writer::set_format_helper(struct archive *ar, int format) { std::string error_msg; switch(format) { case Archive::FORMAT_AR_BSD: archive_write_set_format_ar_bsd(ar); break; case Archive::FORMAT_AR_SVR4: archive_write_set_format_ar_svr4(ar); break; case Archive::FORMAT_CPIO: archive_write_set_format_cpio(ar); break; case Archive::FORMAT_CPIO_NEWC: archive_write_set_format_cpio_newc(ar); break; case Archive::FORMAT_MTREE: archive_write_set_format_mtree(ar); break; case Archive::FORMAT_TAR: case Archive::FORMAT_TAR_PAX_RESTRICTED: archive_write_set_format_pax_restricted(ar); break; case Archive::FORMAT_TAR_PAX_INTERCHANGE: archive_write_set_format_pax(ar); break; case Archive::FORMAT_TAR_USTAR: archive_write_set_format_ustar(ar); break; default: error_msg = "unknown or unsupported archive format"; throw Error(error_msg); } }
// Based on libarchive's public example code. // https://github.com/libarchive/libarchive/wiki/Examples#wiki-A_Basic_Write_Example void GuiZipper::packageFiles(const char *outputFile, const char *baseDir, char **filenames, int numFiles, bool binary, const char *absMetaFilename, const char *metaFilename) throw (ZipperException*) { int r; struct archive *a = archive_write_new(); r = archive_write_add_filter_gzip(a); checkForErrors("Error adding filter gzip", a, r); r = archive_write_set_format_pax_restricted(a); checkForErrors("Error setting format pax restricted", a, r); r = archive_write_open_filename(a, outputFile); checkForErrors("Error opening file", a, r); packageSingleFile(absMetaFilename, metaFilename, a, false); for (int x = 0; x < numFiles; x++) { char *filename = filenames[x]; char *filePath = fileManager_->getFilePath(baseDir, filename); try { packageSingleFile(filePath, filename, a, binary); } catch (ZipperException *ze) { delete filePath; throw ze; } delete filePath; } r = archive_write_close(a); checkForErrors("Error writing close", a, r); r = archive_write_free(a); checkForErrors("Error writing free", a, r); }
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 repodata_flush(struct xbps_handle *xhp, const char *repodir, xbps_dictionary_t idx, xbps_dictionary_t idxfiles) { struct archive *ar; mode_t myumask; char *repofile, *tname, *xml; int repofd; /* Create a tempfile for our repository archive */ repofile = xbps_repo_path(xhp, repodir); tname = xbps_xasprintf("%s.XXXXXXXXXX", repofile); if ((repofd = mkstemp(tname)) == -1) return errno; /* Create and write our repository archive */ ar = archive_write_new(); assert(ar); archive_write_set_compression_gzip(ar); archive_write_set_format_pax_restricted(ar); archive_write_set_options(ar, "compression-level=9"); archive_write_open_fd(ar, repofd); xml = xbps_dictionary_externalize(idx); assert(xml); if (xbps_archive_append_buf(ar, xml, strlen(xml), XBPS_PKGINDEX, 0644, "root", "root") != 0) { free(xml); return -1; } free(xml); xml = xbps_dictionary_externalize(idxfiles); assert(xml); if (xbps_archive_append_buf(ar, xml, strlen(xml), XBPS_PKGINDEX_FILES, 0644, "root", "root") != 0) { free(xml); return -1; } free(xml); archive_write_finish(ar); /* Write data to tempfile and rename */ fdatasync(repofd); myumask = umask(0); (void)umask(myumask); assert(fchmod(repofd, 0666 & ~myumask) != -1); close(repofd); rename(tname, repofile); free(repofile); free(tname); return 0; }
static gboolean asb_utils_write_archive (const gchar *filename, const gchar *path_orig, GPtrArray *files, GError **error) { const gchar *tmp; gboolean ret = TRUE; gsize len; guint i; struct archive *a; struct archive_entry *entry; struct stat st; a = archive_write_new (); if (g_str_has_suffix (filename, ".gz")) { archive_write_add_filter_gzip (a); archive_write_set_filter_option (a, "gzip", "timestamp", NULL); } if (g_str_has_suffix (filename, ".bz2")) archive_write_add_filter_bzip2 (a); if (g_str_has_suffix (filename, ".xz")) archive_write_add_filter_xz (a); archive_write_set_format_pax_restricted (a); archive_write_open_filename (a, filename); for (i = 0; i < files->len; i++) { g_autofree gchar *data = NULL; g_autofree gchar *filename_full = NULL; tmp = g_ptr_array_index (files, i); filename_full = g_build_filename (path_orig, tmp, NULL); if (stat (filename_full, &st) != 0) continue; entry = archive_entry_new (); archive_entry_set_pathname (entry, tmp); archive_entry_set_size (entry, st.st_size); archive_entry_set_filetype (entry, AE_IFREG); archive_entry_set_perm (entry, 0644); archive_write_header (a, entry); ret = g_file_get_contents (filename_full, &data, &len, error); if (!ret) { archive_entry_free (entry); break; } archive_write_data (a, data, len); archive_entry_free (entry); } archive_write_close (a); archive_write_free (a); return ret; }
void tar_mode_c(struct bsdtar *bsdtar) { struct archive *a; const void *filter_name; int r; if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) lafe_errc(1, 0, "no files or directories specified"); a = archive_write_new(); /* Support any format that the library supports. */ if (cset_get_format(bsdtar->cset) == NULL) { r = archive_write_set_format_pax_restricted(a); cset_set_format(bsdtar->cset, "pax restricted"); } else { r = archive_write_set_format_by_name(a, cset_get_format(bsdtar->cset)); } if (r != ARCHIVE_OK) { fprintf(stderr, "Can't use format %s: %s\n", cset_get_format(bsdtar->cset), archive_error_string(a)); usage(); } archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); r = cset_write_add_filters(bsdtar->cset, a, &filter_name); if (r < ARCHIVE_WARN) { lafe_errc(1, 0, "Unsupported compression option --%s", (const char *)filter_name); } set_writer_options(bsdtar, a); if (bsdtar->passphrase != NULL) r = archive_write_set_passphrase(a, bsdtar->passphrase); else r = archive_write_set_passphrase_callback(a, bsdtar, &passphrase_callback); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(a)); if (ARCHIVE_OK != archive_write_open_filename(a, bsdtar->filename)) lafe_errc(1, 0, "%s", archive_error_string(a)); write_archive(a, bsdtar); }
int packing_init(struct packing **pack, const char *path, pkg_formats format) { char archive_path[MAXPATHLEN]; const char *ext; assert(pack != NULL); *pack = xcalloc(1, sizeof(struct packing)); (*pack)->aread = archive_read_disk_new(); archive_read_disk_set_standard_lookup((*pack)->aread); archive_read_disk_set_symlink_physical((*pack)->aread); (*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; } (*pack)->resolver = archive_entry_linkresolver_new(); archive_entry_linkresolver_set_strategy((*pack)->resolver, archive_format((*pack)->awrite)); return (EPKG_OK); }
void errorReporterClose(ErrorReporter self) { #if HAVE_LIBARCHIVE struct archive* outArchive; CharString outputFilename = newCharString(); LinkedList reportContents = newLinkedList(); #endif // Always do this, just in case flushErrorLog(); #if HAVE_LIBARCHIVE // In case any part of the error report causes a segfault, this function will // be called recursively. A mutex would really be a better solution here, but // this will also work just fine. if(!self->completed) { self->completed = true; buildAbsolutePath(self->desktopPath, self->reportName, "tar.gz", outputFilename); listDirectory(self->reportDirPath->data, reportContents); if(self != NULL) { outArchive = archive_write_new(); archive_write_set_compression_gzip(outArchive); archive_write_set_format_pax_restricted(outArchive); archive_write_open_filename(outArchive, outputFilename->data); linkedListForeach(reportContents, _remapFileToErrorReportRelativePath, self); chdir(self->desktopPath->data); linkedListForeach(reportContents, _addFileToArchive, outArchive); archive_write_close(outArchive); archive_write_free(outArchive); } // Remove original error report removeDirectory(self->reportDirPath); } #endif printf("\n=== Error report complete ===\n"); printf("Created error report at %s\n", self->reportDirPath->data); #if HAVE_LIBARCHIVE printf("Please email the report to: %s\n", SUPPORT_EMAIL); #else printf("Please compress and email the report to: %s\n", SUPPORT_EMAIL); #endif printf("Thanks!\n"); }
Status Carver::compress(const std::set<boost::filesystem::path>& paths) { auto arch = archive_write_new(); if (arch == nullptr) { return Status(1, "Failed to create tar archive"); } // Zipping doesn't seem to be working currently // archive_write_set_format_zip(arch); archive_write_set_format_pax_restricted(arch); auto ret = archive_write_open_filename(arch, archivePath_.string().c_str()); if (ret == ARCHIVE_FATAL) { archive_write_free(arch); return Status(1, "Failed to open tar archive for writing"); } for (const auto& f : paths) { PlatformFile pFile(f.string(), PF_OPEN_EXISTING | PF_READ); auto entry = archive_entry_new(); archive_entry_set_pathname(entry, f.leaf().string().c_str()); archive_entry_set_size(entry, pFile.size()); archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_perm(entry, 0644); // archive_entry_set_atime(); // archive_entry_set_ctime(); // archive_entry_set_mtime(); archive_write_header(arch, entry); // TODO: Chunking or a max file size. std::ifstream in(f.string(), std::ios::binary); std::stringstream buffer; buffer << in.rdbuf(); archive_write_data(arch, buffer.str().c_str(), buffer.str().size()); in.close(); archive_entry_free(entry); } archive_write_free(arch); PlatformFile archFile(archivePath_.string(), PF_OPEN_EXISTING | PF_READ); updateCarveValue(carveGuid_, "size", std::to_string(archFile.size())); updateCarveValue( carveGuid_, "sha256", hashFromFile(HashType::HASH_TYPE_SHA256, archivePath_.string())); return Status(0, "Ok"); };
void Package::pack() { struct archive *a; char buf[8192]; std::string package_base_filename(mManifest.packageName() + "-" + std::to_string(mManifest.packageVersion()) + "-" + mManifest.targetArch()); std::string tbz2_path = mWorkDir.string() + "/" + package_base_filename + ".rps"; a = archive_write_new(); archive_write_add_filter_bzip2(a); archive_write_set_format_pax_restricted(a); archive_write_open_filename(a, tbz2_path.c_str()); struct stat st; struct archive_entry *entry; for (auto &f: mManifest.files()) { std::string source = mUnpackedDir.string() + std::string("/data/") + f.name(); std::string dest = std::string("data/") + f.name(); stat(source.c_str(), &st); entry = archive_entry_new(); archive_entry_set_pathname(entry, dest.c_str()); archive_entry_set_size(entry, st.st_size); archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_perm(entry, 0644); archive_write_header(a, entry); int fd = open(source.c_str(), O_RDONLY); int len = read(fd, buf, sizeof(buf)); while (len > 0) { archive_write_data(a, buf, len); len = read(fd, buf, sizeof(buf)); } close(fd); archive_entry_free(entry); } archive_write_close(a); archive_write_free(a); }
// This function will create a gzipped tar file (outname) // which contains the files matched by the function pattern_match. // Pattern_match should return 0 on no match and 1 on match. int create_archive(char *outname, char *path, const std::vector<std::string> &filenames) { struct archive *a; struct archive_entry *entry; struct stat st; char buff[BUFFER_SIZE]; int len; int fd; a = archive_write_new(); archive_write_set_compression_gzip(a); archive_write_set_format_pax_restricted(a); archive_write_open_filename(a, outname); for (unsigned int i=0;i<filenames.size();i++) { stat(filenames[i].c_str(), &st); entry = archive_entry_new(); archive_entry_set_pathname(entry, filenames[i].c_str()); archive_entry_set_size(entry, st.st_size); archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_perm(entry, 0644); archive_write_header(a, entry); fd = open(filenames[i].c_str(), O_RDONLY); len = read(fd, buff, sizeof(buff)); while (len > 0) { archive_write_data(a, buff, len); len = read(fd, buff, sizeof(buff)); } close(fd); } archive_write_close(a); archive_write_finish(a); return 0; }
static db_writer_t *db_writer_new(repo_t *repo, file_t *db) { db_writer_t *writer = malloc(sizeof(db_writer_t)); writer->archive = archive_write_new(); writer->entry = archive_entry_new(); switch (repo->compression) { case COMPRESS_NONE: archive_write_add_filter_none(writer->archive); break; case COMPRESS_GZIP: archive_write_add_filter_gzip(writer->archive); break; case COMPRESS_BZIP2: archive_write_add_filter_bzip2(writer->archive); break; case COMPRESS_XZ: archive_write_add_filter_xz(writer->archive); break; case COMPRESS_COMPRESS: archive_write_add_filter_compress(writer->archive); break; } archive_write_set_format_pax_restricted(writer->archive); writer->fd = openat(repo->dirfd, db->file, O_CREAT | O_WRONLY | O_TRUNC, 0644); if (writer->fd < 0) err(EXIT_FAILURE, "failed to open %s for writing", db->file); if (flock(writer->fd, LOCK_EX) < 0) err(EXIT_FAILURE, "failed to lock %s", db->file); archive_write_open_fd(writer->archive, writer->fd); buffer_init(&writer->buf, 1024); return writer; }
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); }
static void test_filename(const char *prefix, int dlen, int flen) { char buff[8192]; char filename[400]; char dirname[400]; struct archive_entry *ae; struct archive *a; size_t used; char *p; int i; p = filename; if (prefix) { strcpy(filename, prefix); p += strlen(p); } if (dlen > 0) { for (i = 0; i < dlen; i++) *p++ = 'a'; *p++ = '/'; } for (i = 0; i < flen; i++) *p++ = 'b'; *p = '\0'; strcpy(dirname, filename); /* Create a new archive in memory. */ assert((a = archive_write_new()) != NULL); assertA(0 == archive_write_set_format_pax_restricted(a)); assertA(0 == archive_write_set_compression_none(a)); assertA(0 == archive_write_set_bytes_per_block(a,0)); assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used)); /* * Write a file to it. */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, filename); archive_entry_set_mode(ae, S_IFREG | 0755); failure("Pathname %d/%d", dlen, flen); assertA(0 == archive_write_header(a, ae)); archive_entry_free(ae); /* * Write a dir to it (without trailing '/'). */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, dirname); archive_entry_set_mode(ae, S_IFDIR | 0755); failure("Dirname %d/%d", dlen, flen); assertA(0 == archive_write_header(a, ae)); archive_entry_free(ae); /* Tar adds a '/' to directory names. */ strcat(dirname, "/"); /* * Write a dir to it (with trailing '/'). */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, dirname); archive_entry_set_mode(ae, S_IFDIR | 0755); failure("Dirname %d/%d", dlen, flen); assertA(0 == archive_write_header(a, ae)); archive_entry_free(ae); /* Close out the archive. */ assertA(0 == archive_write_close(a)); #if ARCHIVE_VERSION_NUMBER < 2000000 archive_write_finish(a); #else assertA(0 == archive_write_finish(a)); #endif /* * Now, read the data back. */ assert((a = archive_read_new()) != NULL); assertA(0 == archive_read_support_format_all(a)); assertA(0 == archive_read_support_compression_all(a)); assertA(0 == archive_read_open_memory(a, buff, used)); /* Read the file and check the filename. */ assertA(0 == archive_read_next_header(a, &ae)); #if ARCHIVE_VERSION_NUMBER < 1009000 skipping("Leading '/' preserved on long filenames"); #else assertEqualString(filename, archive_entry_pathname(ae)); #endif assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae)); /* * Read the two dirs and check the names. * * Both dirs should read back with the same name, since * tar should add a trailing '/' to any dir that doesn't * already have one. We only report the first such failure * here. */ assertA(0 == archive_read_next_header(a, &ae)); #if ARCHIVE_VERSION_NUMBER < 1009000 skipping("Trailing '/' preserved on dirnames"); #else assertEqualString(dirname, archive_entry_pathname(ae)); #endif assert((S_IFDIR | 0755) == archive_entry_mode(ae)); assertA(0 == archive_read_next_header(a, &ae)); #if ARCHIVE_VERSION_NUMBER < 1009000 skipping("Trailing '/' added to dir names"); #else assertEqualString(dirname, archive_entry_pathname(ae)); #endif assert((S_IFDIR | 0755) == archive_entry_mode(ae)); /* Verify the end of the archive. */ assert(1 == archive_read_next_header(a, &ae)); assert(0 == archive_read_close(a)); #if ARCHIVE_VERSION_NUMBER < 2000000 archive_read_finish(a); #else assert(0 == archive_read_finish(a)); #endif }
/* ArchiveWriter::__construct {{{ * */ ZEND_METHOD(ArchiveWriter, __construct) { archive_file_t *arch = NULL; int resource_id; zval *this = getThis(); const char *error_string = NULL; char *filename; long error_num, filename_len, result, format=0, compression=0; 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, "s|ll", &filename, &filename_len, &format, &compression) == FAILURE) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } #if PHP_API_VERSION < 20100412 if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } #endif if (php_check_open_basedir(filename TSRMLS_CC)) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } arch = (archive_file_t *) emalloc(sizeof(archive_file_t)); arch->stream = NULL; ALLOC_HASHTABLE(arch->entries); zend_hash_init(arch->entries, 10, NULL, _archive_entries_hash_dtor, 0); arch->mode = PHP_ARCHIVE_WRITE_MODE; arch->buf = emalloc(PHP_ARCHIVE_BUF_LEN + 1); arch->filename = estrndup(filename, filename_len); arch->arch = archive_write_new(); switch (compression) { case PHP_ARCHIVE_COMPRESSION_GZIP: if (archive_write_add_filter_gzip(arch->arch) != ARCHIVE_OK) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Gzip compression is not supported in this build"); zend_restore_error_handling(&error_handling TSRMLS_CC); return; } break; case PHP_ARCHIVE_COMPRESSION_BZIP2: if (archive_write_add_filter_bzip2(arch->arch) != ARCHIVE_OK) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bzip2 compression is not supported in this build"); zend_restore_error_handling(&error_handling TSRMLS_CC); return; } break; case 0: /* default value */ case PHP_ARCHIVE_COMPRESSION_NONE: /* always supported */ break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported compression type %ld", compression); zend_restore_error_handling(&error_handling TSRMLS_CC); return; break; } switch (format) { case 0: /* default value */ case PHP_ARCHIVE_FORMAT_TAR: case PHP_ARCHIVE_FORMAT_PAX_RESTRICTED: archive_write_set_format_pax_restricted(arch->arch); break; case PHP_ARCHIVE_FORMAT_PAX: archive_write_set_format_pax(arch->arch); break; case PHP_ARCHIVE_FORMAT_CPIO: archive_write_set_format_cpio(arch->arch); break; case PHP_ARCHIVE_FORMAT_SHAR: archive_write_set_format_shar(arch->arch); break; case PHP_ARCHIVE_FORMAT_USTAR: archive_write_set_format_ustar(arch->arch); break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported archive format: %ld", format); zend_restore_error_handling(&error_handling TSRMLS_CC); return; break; } archive_write_set_bytes_per_block(arch->arch, DEFAULT_BYTES_PER_BLOCK); result = archive_write_open(arch->arch, arch, _archive_open_clbk, _archive_write_clbk, _archive_close_clbk); /* do not pad the last block */ archive_write_set_bytes_in_last_block(arch->arch, 1); if (result) { error_num = archive_errno(arch->arch); error_string = archive_error_string(arch->arch); efree(arch->filename); efree(arch->buf); efree(arch); if (error_num && error_string) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open file %s for writing: error #%ld, %s", filename, error_num, error_string); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open file %s for writing: unknown error %ld", filename, result); } zend_restore_error_handling(&error_handling TSRMLS_CC); return; } resource_id = zend_list_insert(arch,le_archive); add_property_resource(this, "fd", resource_id); zend_restore_error_handling(&error_handling TSRMLS_CC); return; }
static void make_dist(const char *pkg, const char *suffix, const package_t *plist) { char *archive_name; const char *owner, *group; const plist_t *p; struct archive *archive; struct archive_entry *entry, *sparse_entry; struct archive_entry_linkresolver *resolver; char *initial_cwd; archive = archive_write_new(); archive_write_set_format_pax_restricted(archive); if ((resolver = archive_entry_linkresolver_new()) == NULL) errx(2, "cannot create link resolver"); archive_entry_linkresolver_set_strategy(resolver, archive_format(archive)); if (CompressionType == NULL) { if (strcmp(suffix, "tbz") == 0 || strcmp(suffix, "tar.bz2") == 0) CompressionType = "bzip2"; else if (strcmp(suffix, "tgz") == 0 || strcmp(suffix, "tar.gz") == 0) CompressionType = "gzip"; else CompressionType = "none"; } if (strcmp(CompressionType, "bzip2") == 0) archive_write_set_compression_bzip2(archive); else if (strcmp(CompressionType, "gzip") == 0) archive_write_set_compression_gzip(archive); else if (strcmp(CompressionType, "xz") == 0) archive_write_set_compression_xz(archive); else if (strcmp(CompressionType, "none") == 0) archive_write_set_compression_none(archive); else errx(1, "Unspported compression type for -F: %s", CompressionType); archive_name = xasprintf("%s.%s", pkg, suffix); if (archive_write_open_file(archive, archive_name)) errx(2, "cannot create archive: %s", archive_error_string(archive)); free(archive_name); owner = DefaultOwner; group = DefaultGroup; write_meta_file(contents_file, archive); write_meta_file(comment_file, archive); write_meta_file(desc_file, archive); if (Install) write_meta_file(install_file, archive); if (DeInstall) write_meta_file(deinstall_file, archive); if (Display) write_meta_file(display_file, archive); if (BuildVersion) write_meta_file(build_version_file, archive); if (BuildInfo) write_meta_file(build_info_file, archive); if (SizePkg) write_meta_file(size_pkg_file, archive); if (SizeAll) write_meta_file(size_all_file, archive); if (Preserve) write_meta_file(preserve_file, archive); if (create_views) write_meta_file(views_file, archive); initial_cwd = getcwd(NULL, 0); for (p = plist->head; p; p = p->next) { if (p->type == PLIST_FILE) { write_normal_file(p->name, archive, resolver, owner, group); } else if (p->type == PLIST_CWD) { chdir(p->name); } else if (p->type == PLIST_IGNORE) { p = p->next; } else if (p->type == PLIST_CHOWN) { if (p->name != NULL) owner = p->name; else owner = DefaultOwner; } else if (p->type == PLIST_CHGRP) { if (p->name != NULL) group = p->name; else group = DefaultGroup; } } entry = NULL; archive_entry_linkify(resolver, &entry, &sparse_entry); while (entry != NULL) { write_entry(archive, entry); entry = NULL; archive_entry_linkify(resolver, &entry, &sparse_entry); } archive_entry_linkresolver_free(resolver); if (archive_write_close(archive)) errx(2, "cannot finish archive: %s", archive_error_string(archive)); archive_write_finish(archive); free(initial_cwd); }
static int process_package(rpmts ts, char * filename) { FD_t fdi; FD_t gzdi; Header h; int rc = 0; char * rpmio_flags = NULL; struct archive *a; struct archive_entry *entry; if (!strcmp(filename, "-")) { fdi = fdDup(STDIN_FILENO); } else { fdi = Fopen(filename, "r.ufdio"); } if (Ferror(fdi)) { fprintf(stderr, "rpm2archive: %s: %s\n", filename, Fstrerror(fdi)); exit(EXIT_FAILURE); } rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h); switch (rc) { case RPMRC_OK: case RPMRC_NOKEY: case RPMRC_NOTTRUSTED: break; case RPMRC_NOTFOUND: fprintf(stderr, _("argument is not an RPM package\n")); exit(EXIT_FAILURE); break; case RPMRC_FAIL: default: fprintf(stderr, _("error reading header from package\n")); exit(EXIT_FAILURE); break; } /* Retrieve payload size and compression type. */ { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); } gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ free(rpmio_flags); if (gzdi == NULL) { fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); exit(EXIT_FAILURE); } rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); rpmfi fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST); /* create archive */ a = archive_write_new(); archive_write_add_filter_gzip(a); archive_write_set_format_pax_restricted(a); if (!strcmp(filename, "-")) { if (isatty(STDOUT_FILENO)) { fprintf(stderr, "Error: refusing to output archive data to a terminal.\n"); exit(EXIT_FAILURE); } archive_write_open_fd(a, STDOUT_FILENO); } else { char * outname = rstrscat(NULL, filename, ".tgz", NULL); archive_write_open_filename(a, outname); _free(outname); // XXX error handling } entry = archive_entry_new(); char * buf = xmalloc(BUFSIZE); char * hardlink = NULL; rc = 0; while (rc >= 0) { rc = rpmfiNext(fi); if (rc == RPMERR_ITER_END) { break; } rpm_mode_t mode = rpmfiFMode(fi); int nlink = rpmfiFNlink(fi); fill_archive_entry(a, entry, fi); if (nlink > 1) { if (rpmfiArchiveHasContent(fi)) { _free(hardlink); hardlink = rstrscat(NULL, ".", rpmfiFN(fi), NULL); } else { archive_entry_set_hardlink(entry, hardlink); } } archive_write_header(a, entry); if (S_ISREG(mode) && (nlink == 1 || rpmfiArchiveHasContent(fi))) { write_file_content(a, buf, fi); } } /* End of iteration is not an error */ if (rc == RPMERR_ITER_END) { rc = 0; } _free(hardlink); Fclose(gzdi); /* XXX gzdi == fdi */ archive_entry_free(entry); archive_write_close(a); archive_write_free(a); buf = _free(buf); rpmfilesFree(files); rpmfiFree(fi); headerFree(h); return rc; }
RESULTCODE ArchiveProcessorImpl::Compress() { const char* tpath = GetArchivePath(); if(tpath==NULL) { return AG_FAILURE; } struct archive *a; struct archive_entry *entry; struct stat st; char buff[AUGE_BUFFER_MAX]; int len; int fd; a = archive_write_new(); if(a==NULL) { return AG_FAILURE; } //archive_write_add_filter_gzip(a); archive_write_set_format_zip(a); archive_write_set_format_pax_restricted(a); archive_write_open_filename(a,tpath); const char* fpath = NULL; char name[AUGE_NAME_MAX]; char ext[AUGE_EXT_MAX]; char fname[AUGE_NAME_MAX]; std::vector<std::string>::iterator iter; for(iter=m_paths.begin(); iter!=m_paths.end();iter++) { fpath = (*iter).c_str(); memset(fname,0,AUGE_NAME_MAX); memset(name,0,AUGE_NAME_MAX); memset(name,0,AUGE_EXT_MAX); auge_split_path(fpath, NULL, NULL, name, ext); auge_make_path(fname, NULL, NULL, name, ext); if(strlen(fname)==0) { continue; } stat(fpath,&st); entry = archive_entry_new(); archive_entry_set_pathname(entry,fname); archive_entry_set_size(entry,st.st_size); archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_perm(entry,0644); archive_write_header(a,entry); fd = open(fpath,O_RDONLY); len = read(fd,buff,sizeof(buff)); while(len>0) { archive_write_data(a,buff, len); len = read(fd,buff,sizeof(buff)); } close(fd); archive_entry_free(entry); } archive_write_close(a); archive_write_free(a); return AG_SUCCESS; }
/* * Archiving related functions. * This one creates a list of files to be included into the archive and * sets up the libarchive context. */ int setup_archiver(pc_ctx_t *pctx, struct stat *sbuf) { char *tmpfile, *tmp; int err, fd; uchar_t *pbuf; struct archive *arc; struct fn_list *fn; /* * If sorting is enabled create the initial sort buffer. */ if (pctx->enable_archive_sort) { struct sort_buf *srt; srt = (struct sort_buf *)malloc(sizeof (struct sort_buf)); if (srt == NULL) { log_msg(LOG_ERR, 0, "Out of memory."); return (-1); } srt->next = NULL; srt->pos = 0; pctx->archive_sort_buf = srt; } /* * Create a temporary file to hold the generated list of pathnames to be archived. * Storing in a file saves memory usage and allows scalability. */ tmpfile = pctx->archive_members_file; tmp = get_temp_dir(); strcpy(tmpfile, tmp); free(tmp); strcat(tmpfile, "/.pcompXXXXXX"); if ((fd = mkstemp(tmpfile)) == -1) { log_msg(LOG_ERR, 1, "mkstemp errored."); return (-1); } add_fname(tmpfile); pbuf = malloc(pctx->chunksize); if (pbuf == NULL) { log_msg(LOG_ERR, 0, "Out of memory."); close(fd); unlink(tmpfile); return (-1); } /* * Use nftw() to scan all the directory hierarchies provided on the command * line and generate a consolidated list of pathnames to be archived. By * doing this we can sort the pathnames and estimate the total archive size. * Total archive size is needed by the subsequent compression stages. */ log_msg(LOG_INFO, 0, "Scanning files."); sbuf->st_size = 0; pctx->archive_size = 0; pctx->archive_members_count = 0; /* * nftw requires using global state variable. So we lock to be mt-safe. * This means only one directory tree scan can happen at a time. */ pthread_mutex_lock(&nftw_mutex); fn = pctx->fn; a_state.pbuf = pbuf; a_state.bufsiz = pctx->chunksize; a_state.bufpos = 0; a_state.fd = fd; a_state.srt = pctx->archive_sort_buf; a_state.srt_pos = 0; a_state.head = a_state.srt; a_state.pathlist_size = 0; while (fn) { struct stat sb; if (lstat(fn->filename, &sb) == -1) { log_msg(LOG_ERR, 1, "Ignoring %s.", fn->filename); fn = fn->next; continue; } a_state.arc_size = 0; a_state.fcount = 0; if (S_ISDIR(sb.st_mode)) { /* * Depth-First scan, FTW_DEPTH, is needed to handle restoring * all directory permissions correctly. */ err = nftw(fn->filename, add_pathname, 1024, FTW_PHYS | FTW_DEPTH); } else { int tflag; struct FTW ftwbuf; char *pos; if (S_ISLNK(sb.st_mode)) tflag = FTW_SL; else tflag = FTW_F; /* * Find out basename to mimic FTW. */ pos = strrchr(fn->filename, PATHSEP_CHAR); if (pos) ftwbuf.base = pos - fn->filename + 1; else ftwbuf.base = 0; add_pathname(fn->filename, &sb, tflag, &ftwbuf); a_state.arc_size = sb.st_size; } if (a_state.bufpos > 0) { ssize_t wrtn = Write(a_state.fd, a_state.pbuf, a_state.bufpos); if (wrtn < a_state.bufpos) { log_msg(LOG_ERR, 1, "Write failed."); close(fd); unlink(tmpfile); return (-1); } a_state.bufpos = 0; a_state.pathlist_size += wrtn; } pctx->archive_size += a_state.arc_size; pctx->archive_members_count += a_state.fcount; fn = fn->next; } if (a_state.srt == NULL) { pctx->enable_archive_sort = 0; } else { log_msg(LOG_INFO, 0, "Sorting ..."); a_state.srt->max = a_state.srt_pos - 1; qsort(a_state.srt->members, a_state.srt_pos, sizeof (member_entry_t), compare_members); pctx->archive_temp_size = a_state.pathlist_size; } pthread_mutex_unlock(&nftw_mutex); sbuf->st_size = pctx->archive_size; lseek(fd, 0, SEEK_SET); free(pbuf); sbuf->st_uid = geteuid(); sbuf->st_gid = getegid(); sbuf->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; arc = archive_write_new(); if (!arc) { log_msg(LOG_ERR, 1, "Unable to create libarchive context.\n"); close(fd); unlink(tmpfile); return (-1); } archive_write_set_format_pax_restricted(arc); archive_write_set_bytes_per_block(arc, 0); archive_write_open(arc, pctx, arc_open_callback, creat_write_callback, creat_close_callback); pctx->archive_ctx = arc; pctx->archive_members_fd = fd; if (pctx->enable_archive_sort) { pctx->temp_mmap_len = TEMP_MMAP_SIZE; pctx->temp_mmap_buf = mmap(NULL, pctx->temp_mmap_len, PROT_READ, MAP_SHARED, pctx->archive_members_fd, 0); if (pctx->temp_mmap_buf == NULL) { log_msg(LOG_WARN, 1, "Unable to mmap pathlist file, switching to read()."); pctx->temp_mmap_len = 0; } } else { pctx->temp_mmap_buf = NULL; pctx->temp_mmap_len = 0; } pctx->temp_mmap_pos = 0; pctx->arc_writing = 0; return (0); }
void tarsnap_mode_c(struct bsdtar *bsdtar) { struct archive *a; size_t i; if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) bsdtar_errc(bsdtar, 1, 0, "no files or directories specified"); for (i = 0; bsdtar->argv[i] != NULL; i++) { if (bsdtar->argv[i][0] == '-' && bsdtar->argv[i][1] == '-') { bsdtar_warnc(bsdtar, 0, "List of objects to archive includes '%s'." " This might not be what you intended.", bsdtar->argv[i]); break; } } a = archive_write_new(); /* We only support the pax restricted format. */ archive_write_set_format_pax_restricted(a); /* Set the block size to zero -- we don't want buffering. */ archive_write_set_bytes_per_block(a, 0); /* Open the archive, keeping a cookie for talking to the tape layer. */ bsdtar->write_cookie = archive_write_open_multitape(a, bsdtar->machinenum, bsdtar->cachedir, bsdtar->tapenames[0], bsdtar->argc_orig, bsdtar->argv_orig, bsdtar->option_print_stats, bsdtar->option_dryrun, bsdtar->creationtime); if (bsdtar->write_cookie == NULL) bsdtar_errc(bsdtar, 1, 0, "%s", archive_error_string(a)); /* * Remember the device and inode numbers of the cache directory, so * that we can skip is in write_hierarchy(). */ if (getdevino(a, bsdtar->cachedir, &bsdtar->cachedir_dev, &bsdtar->cachedir_ino)) bsdtar_errc(bsdtar, 1, 0, "%s", archive_error_string(a)); /* If the chunkification cache is enabled, read it. */ if ((bsdtar->cachecrunch < 2) && (bsdtar->cachedir != NULL)) { bsdtar->chunk_cache = ccache_read(bsdtar->cachedir); if (bsdtar->chunk_cache == NULL) bsdtar_errc(bsdtar, 1, errno, "Error reading cache"); } write_archive(a, bsdtar); /* * If this isn't a dry run and we're running with the chunkification * cache enabled, write the cache back to disk. */ if ((bsdtar->option_dryrun == 0) && (bsdtar->cachecrunch < 2)) { if (ccache_write(bsdtar->chunk_cache, bsdtar->cachedir)) bsdtar_errc(bsdtar, 1, errno, "Error writing cache"); } /* Free the chunkification cache. */ if (bsdtar->cachecrunch < 2) ccache_free(bsdtar->chunk_cache); }
void tar_mode_c(struct bsdtar *bsdtar) { struct archive *a; int r; if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) bsdtar_errc(bsdtar, 1, 0, "no files or directories specified"); a = archive_write_new(); /* Support any format that the library supports. */ if (bsdtar->create_format == NULL) { r = archive_write_set_format_pax_restricted(a); bsdtar->create_format = "pax restricted"; } else { r = archive_write_set_format_by_name(a, bsdtar->create_format); } if (r != ARCHIVE_OK) { fprintf(stderr, "Can't use format %s: %s\n", bsdtar->create_format, archive_error_string(a)); usage(bsdtar); } /* * If user explicitly set the block size, then assume they * want the last block padded as well. Otherwise, use the * default block size and accept archive_write_open_file()'s * default padding decisions. */ if (bsdtar->bytes_per_block != 0) { archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); archive_write_set_bytes_in_last_block(a, bsdtar->bytes_per_block); } else archive_write_set_bytes_per_block(a, DEFAULT_BYTES_PER_BLOCK); if (bsdtar->compress_program) { archive_write_set_compression_program(a, bsdtar->compress_program); } else { switch (bsdtar->create_compression) { case 0: archive_write_set_compression_none(a); break; #ifdef HAVE_LIBBZ2 case 'j': case 'y': archive_write_set_compression_bzip2(a); break; #endif #ifdef HAVE_LIBLZMA case 'J': archive_write_set_compression_xz(a); break; case OPTION_LZMA: archive_write_set_compression_lzma(a); break; #endif #ifdef HAVE_LIBZ case 'z': archive_write_set_compression_gzip(a); break; #endif case 'Z': archive_write_set_compression_compress(a); break; default: bsdtar_errc(bsdtar, 1, 0, "Unrecognized compression option -%c", bsdtar->create_compression); } } if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) bsdtar_errc(bsdtar, 1, 0, archive_error_string(a)); if (ARCHIVE_OK != archive_write_open_file(a, bsdtar->filename)) bsdtar_errc(bsdtar, 1, 0, archive_error_string(a)); write_archive(a, bsdtar); }
void tar_mode_c(struct bsdtar *bsdtar) { struct archive *a; int r; if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) lafe_errc(1, 0, "no files or directories specified"); a = archive_write_new(); /* Support any format that the library supports. */ if (bsdtar->create_format == NULL) { r = archive_write_set_format_pax_restricted(a); bsdtar->create_format = "pax restricted"; } else { r = archive_write_set_format_by_name(a, bsdtar->create_format); } if (r != ARCHIVE_OK) { fprintf(stderr, "Can't use format %s: %s\n", bsdtar->create_format, archive_error_string(a)); usage(); } archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); if (bsdtar->compress_program) { archive_write_set_compression_program(a, bsdtar->compress_program); } else { switch (bsdtar->create_compression) { case 0: r = ARCHIVE_OK; break; case 'j': case 'y': r = archive_write_set_compression_bzip2(a); break; case 'J': r = archive_write_set_compression_xz(a); break; case OPTION_LZIP: r = archive_write_set_compression_lzip(a); break; case OPTION_LZMA: r = archive_write_set_compression_lzma(a); break; case 'z': r = archive_write_set_compression_gzip(a); break; case 'Z': r = archive_write_set_compression_compress(a); break; default: lafe_errc(1, 0, "Unrecognized compression option -%c", bsdtar->create_compression); } if (r != ARCHIVE_OK) { lafe_errc(1, 0, "Unsupported compression option -%c", bsdtar->create_compression); } } if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) lafe_errc(1, 0, "%s", archive_error_string(a)); if (ARCHIVE_OK != archive_write_open_file(a, bsdtar->filename)) lafe_errc(1, 0, "%s", archive_error_string(a)); write_archive(a, bsdtar); }
int powaur_backup(alpm_list_t *targets) { int ret = 0; char localdb[PATH_MAX]; struct archive *a; struct archive_entry *entry; struct stat st; char cwd[PATH_MAX]; char backup_dest[PATH_MAX]; char backup[MINI_BUFSZ]; time_t time_now; struct tm tm_st; if (targets != NULL && alpm_list_count(targets) != 1) { pw_fprintf(PW_LOG_ERROR, stderr, "-B only takes 1 argument.\n"); return -1; } a = archive_write_new(); if (!a) { return error(PW_ERR_ARCHIVE_CREATE); } archive_write_set_compression_bzip2(a); archive_write_set_format_pax_restricted(a); /* Filename = pacman-YYYY-MM-DD_HHhMM.tar.bz2 */ time(&time_now); localtime_r(&time_now, &tm_st); strftime(backup, MINI_BUFSZ, "pacman-%Y-%m-%d_%Hh%M.tar.bz2", &tm_st); if (!getcwd(cwd, PATH_MAX)) { error(PW_ERR_GETCWD); ret = -1; goto cleanup; } /* Get full path */ if (targets) { snprintf(backup_dest, PATH_MAX, "%s/%s", targets->data, backup); } else { snprintf(backup_dest, PATH_MAX, "%s/%s", cwd, backup); } if (archive_write_open_filename(a, backup_dest) != ARCHIVE_OK) { PW_SETERRNO(PW_ERR_ARCHIVE_OPEN); ret = -1; goto cleanup; } if (ret = chdir(pacman_dbpath)) { error(PW_ERR_CHDIR, pacman_dbpath); goto restore_cwd; } /* Create entry for the current directory. */ entry = archive_entry_new(); if (!entry) { error(PW_ERR_ARCHIVE_ENTRY); goto restore_cwd; } snprintf(localdb, PATH_MAX, "%s", "local"); if (ret = stat(localdb, &st)) { error(PW_ERR_STAT, localdb); goto free_entry; } archive_entry_set_pathname(entry, localdb); archive_entry_copy_stat(entry, &st); archive_write_header(a, entry); pw_printf(PW_LOG_INFO, "Saving pacman database in %s\n", backup_dest); ret = write_dir_archive(localdb, a); if (!ret) { pw_printf(PW_LOG_INFO, "Pacman database successfully saved in %s\n", backup_dest); } else { pw_fprintf(PW_LOG_ERROR, stderr, "Pacman database not saved.\n"); } free_entry: archive_entry_free(entry); restore_cwd: if (chdir(cwd)) { PW_SETERRNO(PW_ERR_RESTORECWD); ret = -1; } cleanup: archive_write_finish(a); return ret; }
bool LibArchiveInterface::addFiles(const QStringList& files, const CompressionOptions& options) { const bool creatingNewFile = !QFileInfo(filename()).exists(); const QString tempFilename = filename() + QLatin1String( ".arkWriting" ); const QString globalWorkDir = options.value(QLatin1String( "GlobalWorkDir" )).toString(); if (!globalWorkDir.isEmpty()) { kDebug() << "GlobalWorkDir is set, changing dir to " << globalWorkDir; m_workDir.setPath(globalWorkDir); QDir::setCurrent(globalWorkDir); } m_writtenFiles.clear(); ArchiveRead arch_reader; if (!creatingNewFile) { arch_reader.reset(archive_read_new()); if (!(arch_reader.data())) { emit error(i18n("The archive reader could not be initialized.")); return false; } if (archive_read_support_compression_all(arch_reader.data()) != ARCHIVE_OK) { return false; } if (archive_read_support_format_all(arch_reader.data()) != ARCHIVE_OK) { return false; } if (archive_read_open_filename(arch_reader.data(), QFile::encodeName(filename()), 10240) != ARCHIVE_OK) { emit error(i18n("The source file could not be read.")); return false; } } ArchiveWrite arch_writer(archive_write_new()); if (!(arch_writer.data())) { emit error(i18n("The archive writer could not be initialized.")); return false; } //pax_restricted is the libarchive default, let's go with that. archive_write_set_format_pax_restricted(arch_writer.data()); int ret; if (creatingNewFile) { if (filename().right(2).toUpper() == QLatin1String( "GZ" )) { kDebug() << "Detected gzip compression for new file"; ret = archive_write_set_compression_gzip(arch_writer.data()); } else if (filename().right(3).toUpper() == QLatin1String( "BZ2" )) { kDebug() << "Detected bzip2 compression for new file"; ret = archive_write_set_compression_bzip2(arch_writer.data()); #ifdef HAVE_LIBARCHIVE_XZ_SUPPORT } else if (filename().right(2).toUpper() == QLatin1String( "XZ" )) { kDebug() << "Detected xz compression for new file"; ret = archive_write_set_compression_xz(arch_writer.data()); #endif #ifdef HAVE_LIBARCHIVE_LZMA_SUPPORT } else if (filename().right(4).toUpper() == QLatin1String( "LZMA" )) { kDebug() << "Detected lzma compression for new file"; ret = archive_write_set_compression_lzma(arch_writer.data()); #endif } else if (filename().right(3).toUpper() == QLatin1String( "TAR" )) { kDebug() << "Detected no compression for new file (pure tar)"; ret = archive_write_set_compression_none(arch_writer.data()); } else { kDebug() << "Falling back to gzip"; ret = archive_write_set_compression_gzip(arch_writer.data()); } if (ret != ARCHIVE_OK) { emit error(i18nc("@info", "Setting the compression method failed with the following error: <message>%1</message>", QLatin1String(archive_error_string(arch_writer.data())))); return false; } } else { switch (archive_compression(arch_reader.data())) { case ARCHIVE_COMPRESSION_GZIP: ret = archive_write_set_compression_gzip(arch_writer.data()); break; case ARCHIVE_COMPRESSION_BZIP2: ret = archive_write_set_compression_bzip2(arch_writer.data()); break; #ifdef HAVE_LIBARCHIVE_XZ_SUPPORT case ARCHIVE_COMPRESSION_XZ: ret = archive_write_set_compression_xz(arch_writer.data()); break; #endif #ifdef HAVE_LIBARCHIVE_LZMA_SUPPORT case ARCHIVE_COMPRESSION_LZMA: ret = archive_write_set_compression_lzma(arch_writer.data()); break; #endif case ARCHIVE_COMPRESSION_NONE: ret = archive_write_set_compression_none(arch_writer.data()); break; default: emit error(i18n("The compression type '%1' is not supported by Ark.", QLatin1String(archive_compression_name(arch_reader.data())))); return false; } if (ret != ARCHIVE_OK) { emit error(i18nc("@info", "Setting the compression method failed with the following error: <message>%1</message>", QLatin1String(archive_error_string(arch_writer.data())))); return false; } } ret = archive_write_open_filename(arch_writer.data(), QFile::encodeName(tempFilename)); if (ret != ARCHIVE_OK) { emit error(i18nc("@info", "Opening the archive for writing failed with the following error: <message>%1</message>", QLatin1String(archive_error_string(arch_writer.data())))); return false; } //**************** first write the new files foreach(const QString& selectedFile, files) { bool success; success = writeFile(selectedFile, arch_writer.data()); if (!success) { QFile::remove(tempFilename); return false; } if (QFileInfo(selectedFile).isDir()) { QDirIterator it(selectedFile, QDir::AllEntries | QDir::Readable | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); while (it.hasNext()) { const QString path = it.next(); if ((it.fileName() == QLatin1String("..")) || (it.fileName() == QLatin1String("."))) { continue; } const bool isRealDir = it.fileInfo().isDir() && !it.fileInfo().isSymLink(); success = writeFile(path + (isRealDir ? QLatin1String( "/" ) : QLatin1String( "" )), arch_writer.data()); if (!success) { QFile::remove(tempFilename); return false; } } } }
/*! * \brief Create pax archive with all metadata * * \param filename Target archive path * \param base_dir Base directory for \a paths * \param paths List of paths to add to the archive * * \return Whether the archive creation was successful */ bool libarchive_tar_create(const std::string &filename, const std::string &base_dir, const std::vector<std::string> &paths) { if (base_dir.empty() && paths.empty()) { LOGE("%s: No base directory or paths specified", filename.c_str()); return false; } autoclose::archive in(archive_read_disk_new(), archive_read_free); if (!in) { LOGE("%s: Out of memory when creating disk reader", __FUNCTION__); return false; } autoclose::archive out(archive_write_new(), archive_write_free); if (!out) { LOGE("%s: Out of memory when creating archive writer", __FUNCTION__); return false; } autoclose::archive_entry_linkresolver resolver(archive_entry_linkresolver_new(), archive_entry_linkresolver_free); if (!resolver) { LOGE("%s: Out of memory when creating link resolver", __FUNCTION__); return false; } // Set up disk reader parameters archive_read_disk_set_symlink_physical(in.get()); archive_read_disk_set_metadata_filter_callback( in.get(), metadata_filter, nullptr); archive_read_disk_set_behavior(in.get(), LIBARCHIVE_DISK_READER_FLAGS); // We don't want to look up usernames and group names on Android //archive_read_disk_set_standard_lookup(in.get()); // Set up archive writer parameters // NOTE: We are creating POSIX pax archives instead of GNU tar archives // because libarchive's GNU tar writer is very limited. In particular, // it does not support storing sparse file information, xattrs, or // ACLs. Since this information is stored as extended attributes in // the pax archive, the GNU tar tool will not be able to extract any // of this additional metadata. In other words, extracting and // repacking a backup on a Linux machine with GNU tar will render the // backup useless. //archive_write_set_format_gnutar(out.get()); archive_write_set_format_pax_restricted(out.get()); //archive_write_set_compression_bzip2(out.get()); //archive_write_set_compression_gzip(out.get()); //archive_write_set_compression_xz(out.get()); archive_write_set_bytes_per_block(out.get(), 10240); // Set up link resolver parameters archive_entry_linkresolver_set_strategy(resolver.get(), archive_format(out.get())); // Open output file if (archive_write_open_filename(out.get(), filename.c_str()) != ARCHIVE_OK) { LOGE("%s: Failed to open file: %s", filename.c_str(), archive_error_string(out.get())); return false; } archive_entry *entry = nullptr; archive_entry *sparse_entry = nullptr; int ret; std::string full_path; // Add hierarchies for (const std::string &path : paths) { if (path.empty()) { LOGE("%s: Cannot add empty path to the archive", filename.c_str()); return false; } // If the path is absolute, don't append it to the base directory if (path[0] == '/') { full_path = path; } else { full_path = base_dir; if (!full_path.empty() && full_path.back() != '/' && path[0] != '/') { full_path += '/'; } full_path += path; } ret = archive_read_disk_open(in.get(), full_path.c_str()); if (ret != ARCHIVE_OK) { LOGE("%s: %s", full_path.c_str(), archive_error_string(in.get())); return false; } while (true) { archive_entry_free(entry); entry = archive_entry_new(); ret = archive_read_next_header2(in.get(), entry); if (ret == ARCHIVE_EOF) { break; } else if (ret != ARCHIVE_OK) { LOGE("%s: Failed to read next header: %s", full_path.c_str(), archive_error_string(in.get())); archive_entry_free(entry); return false; } if (archive_entry_filetype(entry) != AE_IFREG) { archive_entry_set_size(entry, 0); } // If our current directory tree path is not an absolute path, set // the archive path to the relative path starting at base_dir const char *curpath = archive_entry_pathname(entry); if (curpath && path[0] != '/' && !base_dir.empty()) { std::string relpath; if (!util::relative_path(curpath, base_dir, &relpath)) { LOGE("Failed to compute relative path of %s starting at %s: %s", curpath, base_dir.c_str(), strerror(errno)); archive_entry_free(entry); return false; } if (relpath.empty()) { // If the relative path is empty, then the current path is // the root of the directory tree. We don't need that, so // skip it. continue; } archive_entry_set_pathname(entry, relpath.c_str()); } switch (archive_entry_filetype(entry)) { case AE_IFSOCK: LOGW("%s: Skipping socket", archive_entry_pathname(entry)); continue; default: LOGV("%s", archive_entry_pathname(entry)); break; } archive_entry_linkify(resolver.get(), &entry, &sparse_entry); if (entry) { if (!write_file(in.get(), out.get(), entry)) { archive_entry_free(entry); return false; } archive_entry_free(entry); entry = nullptr; } if (sparse_entry) { if (!write_file(in.get(), out.get(), sparse_entry)) { archive_entry_free(sparse_entry); return false; } archive_entry_free(sparse_entry); sparse_entry = nullptr; } } archive_entry_free(entry); entry = nullptr; archive_read_close(in.get()); } archive_read_disk_set_metadata_filter_callback(in.get(), nullptr, nullptr); entry = nullptr; archive_entry_linkify(resolver.get(), &entry, &sparse_entry); while (entry) { // This tricky code here is to correctly read the contents of the entry // because the disk reader 'in' is pointing at does not have any // information about the entry by this time and using // archive_read_data_block() with the disk reader consequently must // fail. And we hae to re-open the entry to read the contents. ret = archive_read_disk_open(in.get(), archive_entry_sourcepath(entry)); if (ret != ARCHIVE_OK) { LOGE("%s: %s", archive_entry_sourcepath(entry), archive_error_string(in.get())); return false; } // Invoke archive_read_next_header2() to work archive_read_data_block(), // which is called via write_file() without failure. archive_entry *entry2 = archive_entry_new(); ret = archive_read_next_header2(in.get(), entry2); archive_entry_free(entry2); if (ret != ARCHIVE_OK) { LOGE("%s: %s", archive_entry_sourcepath(entry), archive_error_string(in.get())); archive_entry_free(entry); return false; } if (!write_file(in.get(), out.get(), entry)) { archive_entry_free(entry); return false; } archive_entry_free(entry); archive_read_close(in.get()); entry = nullptr; archive_entry_linkify(resolver.get(), &entry, &sparse_entry); } if (archive_write_close(out.get()) != ARCHIVE_OK) { LOGE("%s: %s", filename.c_str(), archive_error_string(out.get())); return false; } return true; }