static void test_linkify_old_cpio(void) { struct archive_entry *entry, *e2; struct archive_entry_linkresolver *resolver; /* Initialize the resolver. */ assert(NULL != (resolver = archive_entry_linkresolver_new())); archive_entry_linkresolver_set_strategy(resolver, ARCHIVE_FORMAT_CPIO_POSIX); /* Create an entry with 2 link and try to linkify it. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test1"); archive_entry_set_ino(entry, 1); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 2); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't have been changed. */ assert(e2 == NULL); assertEqualInt(10, archive_entry_size(entry)); assertEqualString("test1", archive_entry_pathname(entry)); /* Still shouldn't be matched. */ archive_entry_linkify(resolver, &entry, &e2); assert(e2 == NULL); assertEqualString("test1", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); assertEqualInt(10, archive_entry_size(entry)); archive_entry_free(entry); archive_entry_linkresolver_free(resolver); }
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); }
/* * Read in the entire mtree file into memory on the first request. * Then use the next unused file to satisfy each header request. */ static int read_header(struct archive_read *a, struct archive_entry *entry) { struct mtree *mtree; char *p; int r, use_next; mtree = (struct mtree *)(a->format->data); if (mtree->fd >= 0) { close(mtree->fd); mtree->fd = -1; } if (mtree->entries == NULL) { mtree->resolver = archive_entry_linkresolver_new(); if (mtree->resolver == NULL) return ARCHIVE_FATAL; archive_entry_linkresolver_set_strategy(mtree->resolver, ARCHIVE_FORMAT_MTREE); r = read_mtree(a, mtree); if (r != ARCHIVE_OK) return (r); } a->archive.archive_format = mtree->archive_format; a->archive.archive_format_name = mtree->archive_format_name; for (;;) { if (mtree->this_entry == NULL) return (ARCHIVE_EOF); if (strcmp(mtree->this_entry->name, "..") == 0) { mtree->this_entry->used = 1; if (archive_strlen(&mtree->current_dir) > 0) { /* Roll back current path. */ p = mtree->current_dir.s + mtree->current_dir.length - 1; while (p >= mtree->current_dir.s && *p != '/') --p; if (p >= mtree->current_dir.s) --p; mtree->current_dir.length = p - mtree->current_dir.s + 1; } } if (!mtree->this_entry->used) { use_next = 0; r = parse_file(a, entry, mtree, mtree->this_entry, &use_next); if (use_next == 0) return (r); } mtree->this_entry = mtree->this_entry->next; } }
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); }
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); }
/* * Write user-specified files/dirs to opened archive. */ static void write_archive(struct archive *a, struct bsdtar *bsdtar) { const char *arg; struct archive_entry *entry, *sparse_entry; /* Choose a suitable copy buffer size */ bsdtar->buff_size = 64 * 1024; while (bsdtar->buff_size < (size_t)bsdtar->bytes_per_block) bsdtar->buff_size *= 2; /* Try to compensate for space we'll lose to alignment. */ bsdtar->buff_size += 16 * 1024; /* Allocate a buffer for file data. */ if ((bsdtar->buff = malloc(bsdtar->buff_size)) == NULL) lafe_errc(1, 0, "cannot allocate memory"); if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) lafe_errc(1, 0, "cannot create link resolver"); archive_entry_linkresolver_set_strategy(bsdtar->resolver, archive_format(a)); /* Create a read_disk object. */ if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) lafe_errc(1, 0, "Cannot create read_disk object"); /* Tell the read_disk how handle symlink. */ switch (bsdtar->symlink_mode) { case 'H': archive_read_disk_set_symlink_hybrid(bsdtar->diskreader); break; case 'L': archive_read_disk_set_symlink_logical(bsdtar->diskreader); break; default: archive_read_disk_set_symlink_physical(bsdtar->diskreader); break; } /* Register entry filters. */ archive_read_disk_set_matching(bsdtar->diskreader, bsdtar->matching, excluded_callback, bsdtar); archive_read_disk_set_metadata_filter_callback( bsdtar->diskreader, metadata_filter, bsdtar); /* Set the behavior of archive_read_disk. */ archive_read_disk_set_behavior(bsdtar->diskreader, bsdtar->readdisk_flags); archive_read_disk_set_standard_lookup(bsdtar->diskreader); if (bsdtar->names_from_file != NULL) archive_names_from_file(bsdtar, a); while (*bsdtar->argv) { arg = *bsdtar->argv; if (arg[0] == '-' && arg[1] == 'C') { arg += 2; if (*arg == '\0') { bsdtar->argv++; arg = *bsdtar->argv; if (arg == NULL) { lafe_warnc(0, "%s", "Missing argument for -C"); bsdtar->return_value = 1; goto cleanup; } if (*arg == '\0') { lafe_warnc(0, "Meaningless argument for -C: ''"); bsdtar->return_value = 1; goto cleanup; } } set_chdir(bsdtar, arg); } else { if (*arg != '/' && (arg[0] != '@' || arg[1] != '/')) do_chdir(bsdtar); /* Handle a deferred -C */ if (*arg == '@') { if (append_archive_filename(bsdtar, a, arg + 1) != 0) break; } else write_hierarchy(bsdtar, a, arg); } bsdtar->argv++; } archive_read_disk_set_matching(bsdtar->diskreader, NULL, NULL, NULL); archive_read_disk_set_metadata_filter_callback( bsdtar->diskreader, NULL, NULL); entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); while (entry != NULL) { int r; struct archive_entry *entry2; struct archive *disk = bsdtar->diskreader; /* * This tricky code here is to correctly read the cotents * of the entry because the disk reader bsdtar->diskreader * 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 * have to re-open the entry to read the contents. */ /* TODO: Work with -C option as well. */ r = archive_read_disk_open(disk, archive_entry_sourcepath(entry)); if (r != ARCHIVE_OK) { lafe_warnc(archive_errno(disk), "%s", archive_error_string(disk)); bsdtar->return_value = 1; archive_entry_free(entry); continue; } /* * Invoke archive_read_next_header2() to work * archive_read_data_block(), which is called via write_file(), * without failure. */ entry2 = archive_entry_new(); r = archive_read_next_header2(disk, entry2); archive_entry_free(entry2); if (r != ARCHIVE_OK) { lafe_warnc(archive_errno(disk), "%s", archive_error_string(disk)); if (r == ARCHIVE_FATAL) bsdtar->return_value = 1; else archive_read_close(disk); archive_entry_free(entry); continue; } write_file(bsdtar, a, entry); archive_entry_free(entry); archive_read_close(disk); entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); } if (archive_write_close(a)) { lafe_warnc(0, "%s", archive_error_string(a)); bsdtar->return_value = 1; } cleanup: /* Free file data buffer. */ free(bsdtar->buff); archive_entry_linkresolver_free(bsdtar->resolver); bsdtar->resolver = NULL; archive_read_free(bsdtar->diskreader); bsdtar->diskreader = NULL; if (bsdtar->option_totals) { fprintf(stderr, "Total bytes written: %s\n", tar_i64toa(archive_filter_bytes(a, -1))); } archive_write_free(a); }
static void mode_out(struct cpio *cpio) { struct archive_entry *entry, *spare; struct lafe_line_reader *lr; const char *p; int r; if (cpio->option_append) lafe_errc(1, 0, "Append mode not yet supported."); 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); cpio->archive = archive_write_new(); if (cpio->archive == NULL) lafe_errc(1, 0, "Failed to allocate archive object"); switch (cpio->compress) { case 'J': r = archive_write_set_compression_xz(cpio->archive); break; case OPTION_LZMA: r = archive_write_set_compression_lzma(cpio->archive); break; case 'j': case 'y': r = archive_write_set_compression_bzip2(cpio->archive); break; case 'z': r = archive_write_set_compression_gzip(cpio->archive); break; case 'Z': r = archive_write_set_compression_compress(cpio->archive); break; default: r = archive_write_set_compression_none(cpio->archive); break; } if (r < ARCHIVE_WARN) lafe_errc(1, 0, "Requested compression not available"); r = archive_write_set_format_by_name(cpio->archive, cpio->format); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); archive_write_set_bytes_per_block(cpio->archive, cpio->bytes_per_block); cpio->linkresolver = archive_entry_linkresolver_new(); archive_entry_linkresolver_set_strategy(cpio->linkresolver, archive_format(cpio->archive)); /* * The main loop: Copy each file into the output archive. */ r = archive_write_open_file(cpio->archive, cpio->filename); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); 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); /* * The hardlink detection may have queued up a couple of entries * that can now be flushed. */ entry = NULL; archive_entry_linkify(cpio->linkresolver, &entry, &spare); while (entry != NULL) { entry_to_archive(cpio, entry); archive_entry_free(entry); entry = NULL; archive_entry_linkify(cpio->linkresolver, &entry, &spare); } r = archive_write_close(cpio->archive); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); if (!cpio->quiet) { int64_t blocks = (archive_position_uncompressed(cpio->archive) + 511) / 512; fprintf(stderr, "%lu %s\n", (unsigned long)blocks, blocks == 1 ? "block" : "blocks"); } archive_write_finish(cpio->archive); }
/*! * \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; }
static void test_linkify_tar(void) { struct archive_entry *entry, *e2; struct archive_entry_linkresolver *resolver; /* Initialize the resolver. */ assert(NULL != (resolver = archive_entry_linkresolver_new())); archive_entry_linkresolver_set_strategy(resolver, ARCHIVE_FORMAT_TAR_USTAR); /* Create an entry with only 1 link and try to linkify it. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test1"); archive_entry_set_ino(entry, 1); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 1); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't have been changed. */ assert(e2 == NULL); assertEqualInt(10, archive_entry_size(entry)); assertEqualString("test1", archive_entry_pathname(entry)); /* Now, try again with an entry that has 2 links. */ archive_entry_set_pathname(entry, "test2"); archive_entry_set_nlink(entry, 2); archive_entry_set_ino(entry, 2); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't be altered, since it wasn't seen before. */ assert(e2 == NULL); assertEqualString("test2", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); assertEqualInt(10, archive_entry_size(entry)); /* Match again and make sure it does get altered. */ archive_entry_linkify(resolver, &entry, &e2); assert(e2 == NULL); assertEqualString("test2", archive_entry_pathname(entry)); assertEqualString("test2", archive_entry_hardlink(entry)); assertEqualInt(0, archive_entry_size(entry)); /* Dirs should never be matched as hardlinks, regardless. */ archive_entry_set_pathname(entry, "test3"); archive_entry_set_nlink(entry, 2); archive_entry_set_filetype(entry, AE_IFDIR); archive_entry_set_ino(entry, 3); archive_entry_set_hardlink(entry, NULL); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't be altered, since it wasn't seen before. */ assert(e2 == NULL); assertEqualString("test3", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); /* Dir, so it shouldn't get matched. */ archive_entry_linkify(resolver, &entry, &e2); assert(e2 == NULL); assertEqualString("test3", archive_entry_pathname(entry)); assertEqualString(NULL, archive_entry_hardlink(entry)); archive_entry_free(entry); archive_entry_linkresolver_free(resolver); }
static void test_linkify_new_cpio(void) { struct archive_entry *entry, *e2; struct archive_entry_linkresolver *resolver; /* Initialize the resolver. */ assert(NULL != (resolver = archive_entry_linkresolver_new())); archive_entry_linkresolver_set_strategy(resolver, ARCHIVE_FORMAT_CPIO_SVR4_NOCRC); /* Create an entry with only 1 link and try to linkify it. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test1"); archive_entry_set_ino(entry, 1); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 1); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Shouldn't have been changed. */ assert(e2 == NULL); assertEqualInt(10, archive_entry_size(entry)); assertEqualString("test1", archive_entry_pathname(entry)); /* Now, try again with an entry that has 3 links. */ archive_entry_set_pathname(entry, "test2"); archive_entry_set_nlink(entry, 3); archive_entry_set_ino(entry, 2); archive_entry_linkify(resolver, &entry, &e2); /* First time, it just gets swallowed. */ assert(entry == NULL); assert(e2 == NULL); /* Match again. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test3"); archive_entry_set_ino(entry, 2); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 2); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Should get back "test2" and nothing else. */ assertEqualString("test2", archive_entry_pathname(entry)); assertEqualInt(0, archive_entry_size(entry)); archive_entry_free(entry); assert(NULL == e2); archive_entry_free(e2); /* This should be a no-op. */ /* Match a third time. */ assert(NULL != (entry = archive_entry_new())); archive_entry_set_pathname(entry, "test4"); archive_entry_set_ino(entry, 2); archive_entry_set_dev(entry, 2); archive_entry_set_nlink(entry, 3); archive_entry_set_size(entry, 10); archive_entry_linkify(resolver, &entry, &e2); /* Should get back "test3". */ assertEqualString("test3", archive_entry_pathname(entry)); assertEqualInt(0, archive_entry_size(entry)); /* Since "test4" was the last link, should get it back also. */ assertEqualString("test4", archive_entry_pathname(e2)); assertEqualInt(10, archive_entry_size(e2)); archive_entry_free(entry); archive_entry_free(e2); archive_entry_linkresolver_free(resolver); }
/* * Write user-specified files/dirs to opened archive. */ static void write_archive(struct archive *a, struct bsdtar *bsdtar) { const char *arg; struct archive_entry *entry, *sparse_entry; /* Choose a suitable copy buffer size */ bsdtar->buff_size = 64 * 1024; while (bsdtar->buff_size < (size_t)bsdtar->bytes_per_block) bsdtar->buff_size *= 2; /* Try to compensate for space we'll lose to alignment. */ bsdtar->buff_size += 16 * 1024; /* Allocate a buffer for file data. */ if ((bsdtar->buff = malloc(bsdtar->buff_size)) == NULL) lafe_errc(1, 0, "cannot allocate memory"); if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) lafe_errc(1, 0, "cannot create link resolver"); archive_entry_linkresolver_set_strategy(bsdtar->resolver, archive_format(a)); if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) lafe_errc(1, 0, "Cannot create read_disk object"); archive_read_disk_set_standard_lookup(bsdtar->diskreader); if (bsdtar->names_from_file != NULL) archive_names_from_file(bsdtar, a); while (*bsdtar->argv) { arg = *bsdtar->argv; if (arg[0] == '-' && arg[1] == 'C') { arg += 2; if (*arg == '\0') { bsdtar->argv++; arg = *bsdtar->argv; if (arg == NULL) { lafe_warnc(0, "%s", "Missing argument for -C"); bsdtar->return_value = 1; goto cleanup; } if (*arg == '\0') { lafe_warnc(0, "Meaningless argument for -C: ''"); bsdtar->return_value = 1; goto cleanup; } } set_chdir(bsdtar, arg); } else { if (*arg != '/' && (arg[0] != '@' || arg[1] != '/')) do_chdir(bsdtar); /* Handle a deferred -C */ if (*arg == '@') { if (append_archive_filename(bsdtar, a, arg + 1) != 0) break; } else write_hierarchy(bsdtar, a, arg); } bsdtar->argv++; } entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); while (entry != NULL) { write_file(bsdtar, a, entry); archive_entry_free(entry); entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); } if (archive_write_close(a)) { lafe_warnc(0, "%s", archive_error_string(a)); bsdtar->return_value = 1; } cleanup: /* Free file data buffer. */ free(bsdtar->buff); archive_entry_linkresolver_free(bsdtar->resolver); bsdtar->resolver = NULL; archive_read_free(bsdtar->diskreader); bsdtar->diskreader = NULL; if (bsdtar->option_totals) { fprintf(stderr, "Total bytes written: %s\n", tar_i64toa(archive_position_compressed(a))); } archive_write_free(a); }
/* * Write user-specified files/dirs to opened archive. */ static void write_archive(struct archive *a, struct bsdtar *bsdtar) { struct sigaction sa; const char *arg; struct archive_entry *entry, *sparse_entry; /* We want to catch SIGINFO and SIGUSR1. */ siginfo_init(bsdtar); /* We also want to catch SIGQUIT and ^Q. */ if (sigquit_init()) exit(1); /* And SIGUSR2, too. */ sa.sa_handler = sigusr2_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGUSR2, &sa, NULL)) bsdtar_errc(bsdtar, 1, 0, "cannot install signal handler"); /* Allocate a buffer for file data. */ if ((bsdtar->buff = malloc(FILEDATABUFLEN)) == NULL) bsdtar_errc(bsdtar, 1, 0, "cannot allocate memory"); if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) bsdtar_errc(bsdtar, 1, 0, "cannot create link resolver"); archive_entry_linkresolver_set_strategy(bsdtar->resolver, archive_format(a)); if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) bsdtar_errc(bsdtar, 1, 0, "Cannot create read_disk object"); archive_read_disk_set_standard_lookup(bsdtar->diskreader); if (bsdtar->names_from_file != NULL) archive_names_from_file(bsdtar, a); while (*bsdtar->argv) { if (truncate_archive(bsdtar)) break; if (checkpoint_archive(bsdtar, 0)) exit(1); arg = *bsdtar->argv; if (arg[0] == '-' && arg[1] == 'C') { arg += 2; if (*arg == '\0') { bsdtar->argv++; arg = *bsdtar->argv; if (arg == NULL) { bsdtar_warnc(bsdtar, 0, "Missing argument for -C"); bsdtar->return_value = 1; goto cleanup; } if (*arg == '\0') { bsdtar_warnc(bsdtar, 0, "Meaningless argument for -C: ''"); bsdtar->return_value = 1; goto cleanup; } } set_chdir(bsdtar, arg); } else { if (arg[0] != '/' && (arg[0] != '@' || arg[1] != '/') && (arg[0] != '@' || arg[1] != '@')) do_chdir(bsdtar); /* Handle a deferred -C */ if (arg[0] == '@' && arg[1] == '@') { if (append_archive_tarsnap(bsdtar, a, arg + 2) != 0) break; } else if (arg[0] == '@') { if (append_archive_filename(bsdtar, a, arg + 1) != 0) break; } else #if defined(_WIN32) && !defined(__CYGWIN__) write_hierarchy_win(bsdtar, a, arg, write_hierarchy); #else write_hierarchy(bsdtar, a, arg); #endif } bsdtar->argv++; } /* * This code belongs to bsdtar and is used when writing archives in * "new cpio" format. It has no effect in tarsnap, since tarsnap * doesn't write archives in this format; but I'm leaving it in to * make the diffs smaller. */ entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); while (entry != NULL) { write_entry_backend(bsdtar, a, entry, NULL, NULL); archive_entry_free(entry); entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); } if (archive_write_close(a)) { bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); bsdtar->return_value = 1; } cleanup: /* Free file data buffer. */ free(bsdtar->buff); archive_entry_linkresolver_free(bsdtar->resolver); bsdtar->resolver = NULL; archive_read_finish(bsdtar->diskreader); bsdtar->diskreader = NULL; if (bsdtar->option_totals && (bsdtar->return_value == 0)) { fprintf(stderr, "Total bytes written: " BSDTAR_FILESIZE_PRINTF "\n", (BSDTAR_FILESIZE_TYPE)archive_position_compressed(a)); } archive_write_finish(a); /* Restore old SIGINFO + SIGUSR1 handlers. */ siginfo_done(bsdtar); }
/* * Write user-specified files/dirs to opened archive. */ static void write_archive(struct archive *a, struct bsdtar *bsdtar) { const char *arg; struct archive_entry *entry, *sparse_entry; /* We want to catch SIGINFO and SIGUSR1. */ siginfo_init(bsdtar); /* Allocate a buffer for file data. */ if ((bsdtar->buff = malloc(FILEDATABUFLEN)) == NULL) bsdtar_errc(bsdtar, 1, 0, "cannot allocate memory"); if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) bsdtar_errc(bsdtar, 1, 0, "cannot create link resolver"); archive_entry_linkresolver_set_strategy(bsdtar->resolver, archive_format(a)); if ((bsdtar->diskreader = archive_read_disk_new()) == NULL) bsdtar_errc(bsdtar, 1, 0, "Cannot create read_disk object"); archive_read_disk_set_standard_lookup(bsdtar->diskreader); if (bsdtar->names_from_file != NULL) archive_names_from_file(bsdtar, a); while (*bsdtar->argv) { arg = *bsdtar->argv; if (arg[0] == '-' && arg[1] == 'C') { arg += 2; if (*arg == '\0') { bsdtar->argv++; arg = *bsdtar->argv; if (arg == NULL) { bsdtar_warnc(bsdtar, 1, 0, "Missing argument for -C"); bsdtar->return_value = 1; goto cleanup; } } set_chdir(bsdtar, arg); } else { if (*arg != '/' && (arg[0] != '@' || arg[1] != '/')) do_chdir(bsdtar); /* Handle a deferred -C */ if (*arg == '@') { if (append_archive_filename(bsdtar, a, arg + 1) != 0) break; } else #if defined(_WIN32) && !defined(__CYGWIN__) write_hierarchy_win(bsdtar, a, arg, write_hierarchy); #else write_hierarchy(bsdtar, a, arg); #endif } bsdtar->argv++; } entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); while (entry != NULL) { write_entry_backend(bsdtar, a, entry); archive_entry_free(entry); entry = NULL; archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); } if (archive_write_close(a)) { bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); bsdtar->return_value = 1; } cleanup: /* Free file data buffer. */ free(bsdtar->buff); archive_entry_linkresolver_free(bsdtar->resolver); bsdtar->resolver = NULL; archive_read_finish(bsdtar->diskreader); bsdtar->diskreader = NULL; if (bsdtar->option_totals) { fprintf(stderr, "Total bytes written: " BSDTAR_FILESIZE_PRINTF "\n", (BSDTAR_FILESIZE_TYPE)archive_position_compressed(a)); } archive_write_finish(a); /* Restore old SIGINFO + SIGUSR1 handlers. */ siginfo_done(bsdtar); }
static void mode_out(struct cpio *cpio) { unsigned long blocks; struct archive_entry *entry, *spare; struct line_reader *lr; const char *p; int r; if (cpio->option_append) cpio_errc(1, 0, "Append mode not yet supported."); cpio->archive = archive_write_new(); if (cpio->archive == NULL) cpio_errc(1, 0, "Failed to allocate archive object"); switch (cpio->compress) { #ifdef HAVE_BZLIB_H case 'j': case 'y': archive_write_set_compression_bzip2(cpio->archive); break; #endif #ifdef HAVE_ZLIB_H case 'z': archive_write_set_compression_gzip(cpio->archive); break; #endif case 'Z': archive_write_set_compression_compress(cpio->archive); break; default: archive_write_set_compression_none(cpio->archive); break; } r = archive_write_set_format_by_name(cpio->archive, cpio->format); if (r != ARCHIVE_OK) cpio_errc(1, 0, archive_error_string(cpio->archive)); archive_write_set_bytes_per_block(cpio->archive, cpio->bytes_per_block); cpio->linkresolver = archive_entry_linkresolver_new(); archive_entry_linkresolver_set_strategy(cpio->linkresolver, archive_format(cpio->archive)); r = archive_write_open_file(cpio->archive, cpio->filename); if (r != ARCHIVE_OK) cpio_errc(1, 0, archive_error_string(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); /* * The hardlink detection may have queued up a couple of entries * that can now be flushed. */ entry = NULL; archive_entry_linkify(cpio->linkresolver, &entry, &spare); while (entry != NULL) { entry_to_archive(cpio, entry); archive_entry_free(entry); entry = NULL; archive_entry_linkify(cpio->linkresolver, &entry, &spare); } 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); }