int main(int argc, char *argv[]) { struct archive *archive; int fd; fprintf(stderr, "new\n"); archive = archive_read_new(); archive_read_support_compression_all(archive); archive_read_support_format_all(archive); if (argc > 1 && strcmp(argv[1], "null") == 0) { archive = NULL; archive_read_finish(archive); return 0; } if (argc > 1 && strcmp(argv[1], "open") == 0) { printf("%d\n", argc); fd = open("/etc/passwd", O_RDONLY); archive_read_open_fd(archive, fd, 4096); } fprintf(stderr, "finish 1\n"); archive_read_finish(archive); fprintf(stderr, "finish 2\n"); archive_read_finish(archive); fprintf(stderr, "done\n"); return 0; }
struct pkg_vulnerabilities * read_pkg_vulnerabilities_file(const char *path, int ignore_missing, int check_sum) { #ifdef BOOTSTRAP errx(EXIT_FAILURE, "Audit functions are unsupported during bootstrap"); #else struct archive *a; struct pkg_vulnerabilities *pv; int fd; if ((fd = open(path, O_RDONLY)) == -1) { if (errno == ENOENT && ignore_missing) return NULL; err(EXIT_FAILURE, "Cannot open %s", path); } if ((a = archive_read_new()) == NULL) errx(EXIT_FAILURE, "memory allocation failed"); if (archive_read_support_compression_all(a) != ARCHIVE_OK || archive_read_support_format_raw(a) != ARCHIVE_OK || archive_read_open_fd(a, fd, 65536) != ARCHIVE_OK) errx(EXIT_FAILURE, "Cannot open ``%s'': %s", path, archive_error_string(a)); pv = read_pkg_vulnerabilities_archive(a, check_sum); close(fd); return pv; #endif }
int main(int argc, const char **argv) { if (argc > 2) { fprintf(stderr, "Usage: %s [file]\n", argv[0]); exit(1); } struct archive *a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_raw(a); int err; if (argc == 2) err = archive_read_open_filename(a, argv[1], BS); else err = archive_read_open_fd(a, 0, BS); if (err != ARCHIVE_OK) { fprintf(stderr, "Broken archive (1)\n"); exit(1); } struct archive_entry *ae; err = archive_read_next_header(a, &ae); if (err != ARCHIVE_OK) { fprintf(stderr, "Broken archive (2)\n"); exit(1); } (void) archive_read_data_into_fd(a, 1); archive_read_finish(a); exit(0); }
extern int lparchive_open_fd(lparchive_t *handle, int fd) { handle->fd = fd; /* FIXME: add error handling */ (void)archive_read_open_fd(handle->archive, fd, 1024); return 0; }
static int extract_pkg_static(int fd, char *p, int sz) { struct archive *a; struct archive_entry *ae; char *end; int ret, r; ret = -1; a = archive_read_new(); if (a == NULL) { warn("archive_read_new"); return (ret); } archive_read_support_compression_all(a); archive_read_support_format_tar(a); if (lseek(fd, 0, 0) == -1) { warn("lseek"); goto cleanup; } if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { warnx("archive_read_open_fd: %s", archive_error_string(a)); goto cleanup; } ae = NULL; while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { end = strrchr(archive_entry_pathname(ae), '/'); if (end == NULL) continue; if (strcmp(end, "/pkg-static") == 0) { r = archive_read_extract(a, ae, ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); strlcpy(p, archive_entry_pathname(ae), sz); break; } } if (r == ARCHIVE_OK) ret = 0; else warnx("fail to extract pkg-static"); cleanup: archive_read_finish(a); return (ret); }
/** Open an archive for reading and perform the necessary boilerplate. * This takes care of creating the libarchive 'archive' struct, setting up * compression and format options, opening a file descriptor, setting up the * buffer size, and performing a stat on the path once opened. * On error, no file descriptor is opened, and the archive pointer returned * will be set to NULL. * @param handle the context handle * @param path the path of the archive to open * @param buf space for a stat buffer for the given path * @param archive pointer to place the created archive object * @param error error code to set on failure to open archive * @return -1 on failure, >=0 file descriptor on success */ int _alpm_open_archive(alpm_handle_t *handle, const char *path, struct stat *buf, struct archive **archive, alpm_errno_t error) { int fd; size_t bufsize = ALPM_BUFFER_SIZE; errno = 0; if((*archive = archive_read_new()) == NULL) { RET_ERR(handle, ALPM_ERR_LIBARCHIVE, -1); } archive_read_support_compression_all(*archive); archive_read_support_format_all(*archive); _alpm_log(handle, ALPM_LOG_DEBUG, "opening archive %s\n", path); OPEN(fd, path, O_RDONLY); if(fd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); goto error; } if(fstat(fd, buf) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not stat file %s: %s\n"), path, strerror(errno)); goto error; } #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE if(buf->st_blksize > ALPM_BUFFER_SIZE) { bufsize = buf->st_blksize; } #endif if(archive_read_open_fd(*archive, fd, bufsize) != ARCHIVE_OK) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, archive_error_string(*archive)); goto error; } return fd; error: archive_read_finish(*archive); *archive = NULL; if(fd >= 0) { CLOSE(fd); } RET_ERR(handle, error, -1); }
static arc_handle_t arxive_open(int fd) { arc_handle_t ar; if ((ar = arxive_new()) == 0) return 0; if (llseek(fd, 0, SEEK_SET) < 0) return 0; if (archive_read_open_fd(ar, fd, ARC_BLOCKSIZE) < 0) return 0; return ar; }
static int archive_conv_open(struct archive_conv *conv, const struct repo_t *repo) { int r; /* generally, repo files are gzip compressed, but there's no guarantee of * this. in order to be compression-agnostic, use libarchive's reader/writer * methods. this also gives us an opportunity to rewrite the archive as CPIO, * which is marginally faster given our staunch sequential access. */ conv->reponame = repo->name; stpcpy(stpcpy(conv->tmpfile, repo->diskfile), "~"); conv->in = archive_read_new(); conv->out = archive_write_new(); if (conv->in == NULL || conv->out == NULL) { fputs("error: failed to allocate memory for archive objects\n", stderr); return -ENOMEM; } archive_read_support_format_tar(conv->in); archive_read_support_filter_all(conv->in); r = archive_read_open_fd(conv->in, repo->tmpfile.fd, BUFSIZ); if (r != ARCHIVE_OK) { fprintf(stderr, "error: failed to create archive reader for %s: %s\n", repo->name, strerror(archive_errno(conv->in))); r = archive_errno(conv->in); goto open_error; } archive_write_set_format_cpio_newc(conv->out); archive_write_add_filter(conv->out, repo->config->compress); r = archive_write_open_filename(conv->out, conv->tmpfile); if (r != ARCHIVE_OK) { fprintf(stderr, "error: failed to open file for writing: %s: %s\n", conv->tmpfile, strerror(archive_errno(conv->out))); r = archive_errno(conv->out); goto open_error; } return 0; open_error: archive_write_free(conv->out); archive_read_free(conv->in); return -r; }
/* * Extract a non-encoded file. * The header of the 7z archive files is not encoded. */ static void test_copy(int use_open_fd) { const char *refname = "test_read_format_7zip_copy.7z"; struct archive_entry *ae; struct archive *a; char buff[128]; int fd = -1; extract_reference_file(refname); assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (use_open_fd) { fd = open(refname, O_RDONLY | O_BINARY); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_fd(a, fd, 10240)); } else { assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); } /* Verify regular file1. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae)); assertEqualString("file1", archive_entry_pathname(ae)); assertEqualInt(86401, archive_entry_mtime(ae)); assertEqualInt(60, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assert(archive_read_has_encrypted_entries(a) > ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); assertEqualInt(60, archive_read_data(a, buff, sizeof(buff))); assertEqualMem(buff, " ", 4); assertEqualInt(1, archive_file_count(a)); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); if (fd != -1) close(fd); }
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); }
static bool repo_open_local(struct xbps_repo *repo, const char *repofile) { struct stat st; int rv = 0; if (fstat(repo->fd, &st) == -1) { rv = errno; xbps_dbg_printf(repo->xhp, "[repo] `%s' fstat repodata %s\n", repofile, strerror(rv)); return false; } repo->ar = archive_read_new(); archive_read_support_compression_gzip(repo->ar); archive_read_support_format_tar(repo->ar); if (archive_read_open_fd(repo->ar, repo->fd, st.st_blksize) == ARCHIVE_FATAL) { rv = archive_errno(repo->ar); xbps_dbg_printf(repo->xhp, "[repo] `%s' failed to open repodata archive %s\n", repofile, strerror(rv)); return false; } if ((repo->idx = repo_get_dict(repo)) == NULL) { rv = archive_errno(repo->ar); xbps_dbg_printf(repo->xhp, "[repo] `%s' failed to internalize " " index on archive, removing file.\n", repofile); /* broken archive, remove it */ (void)unlink(repofile); return false; } xbps_dictionary_make_immutable(repo->idx); repo->idxmeta = repo_get_dict(repo); if (repo->idxmeta != NULL) { repo->is_signed = true; xbps_dictionary_make_immutable(repo->idxmeta); } return true; }
static char * extract_pkgname(int fd) { package_t plist; plist_t *p; struct archive *a; struct archive_entry *entry; char *buf; ssize_t len; int r; a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_all(a); if (archive_read_open_fd(a, fd, 1024)) { warnx("Cannot open binary package: %s", archive_error_string(a)); archive_read_finish(a); return NULL; } r = archive_read_next_header(a, &entry); if (r != ARCHIVE_OK) { warnx("Cannot extract package name: %s", r == ARCHIVE_EOF ? "EOF" : archive_error_string(a)); archive_read_finish(a); return NULL; } if (strcmp(archive_entry_pathname(entry), "+CONTENTS") != 0) { warnx("Invalid binary package, doesn't start with +CONTENTS"); archive_read_finish(a); return NULL; } if (archive_entry_size(entry) > SSIZE_MAX - 1) { warnx("+CONTENTS too large to process"); archive_read_finish(a); return NULL; } len = archive_entry_size(entry); buf = xmalloc(len + 1); if (archive_read_data(a, buf, len) != len) { warnx("Short read when extracing +CONTENTS"); free(buf); archive_read_finish(a); return NULL; } buf[len] = '\0'; archive_read_finish(a); parse_plist(&plist, buf); free(buf); p = find_plist(&plist, PLIST_NAME); if (p != NULL) { buf = xstrdup(p->name); } else { warnx("Invalid PLIST: missing @name"); buf = NULL; } free_plist(&plist); if (lseek(fd, 0, SEEK_SET) != 0) { warn("Cannot seek in archive"); free(buf); return NULL; } return buf; }
static int repo_archive_extract_file(int fd, const char *file, const char *dest, const char *repokey, int dest_fd) { struct archive *a = NULL; struct archive_entry *ae = NULL; unsigned char *sig = NULL; int siglen = 0, ret, rc = EPKG_OK; a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_tar(a); /* Seek to the begin of file */ (void)lseek(fd, 0, SEEK_SET); archive_read_open_fd(a, fd, 4096); while (archive_read_next_header(a, &ae) == ARCHIVE_OK) { if (strcmp(archive_entry_pathname(ae), file) == 0) { if (dest_fd == -1) { archive_entry_set_pathname(ae, dest); /* * The repo should be owned by root and not writable */ archive_entry_set_uid(ae, 0); archive_entry_set_gid(ae, 0); archive_entry_set_perm(ae, 0644); if (archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS) != 0) { pkg_emit_errno("archive_read_extract", "extract error"); rc = EPKG_FATAL; goto cleanup; } } else { if (archive_read_data_into_fd(a, dest_fd) != 0) { pkg_emit_errno("archive_read_extract", "extract error"); rc = EPKG_FATAL; goto cleanup; } (void)lseek(dest_fd, 0, SEEK_SET); } } if (strcmp(archive_entry_pathname(ae), "signature") == 0) { siglen = archive_entry_size(ae); sig = malloc(siglen); archive_read_data(a, sig, siglen); } } if (repokey != NULL) { if (sig != NULL) { ret = rsa_verify(dest, repokey, sig, siglen - 1, dest_fd); if (ret != EPKG_OK) { pkg_emit_error("Invalid signature, " "removing repository."); if (dest != NULL) unlink(dest); free(sig); rc = EPKG_FATAL; goto cleanup; } free(sig); } else { pkg_emit_error("No signature found in the repository. " "Can not validate against %s key.", repokey); rc = EPKG_FATAL; if (dest != NULL) unlink(dest); goto cleanup; } } cleanup: if (a != NULL) archive_read_free(a); return rc; }
/* * Same as 'c', except we only support tar or empty formats in * uncompressed files on disk. */ void tar_mode_r(struct bsdtar *bsdtar) { off_t end_offset; int format; struct archive *a; struct archive_entry *entry; int r; /* Sanity-test some arguments and the file. */ test_for_append(bsdtar); format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT, 0666); if (bsdtar->fd < 0) bsdtar_errc(bsdtar, 1, errno, "Cannot open %s", bsdtar->filename); a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_tar(a); archive_read_support_format_gnutar(a); r = archive_read_open_fd(a, bsdtar->fd, 10240); if (r != ARCHIVE_OK) bsdtar_errc(bsdtar, 1, archive_errno(a), "Can't read archive %s: %s", bsdtar->filename, archive_error_string(a)); while (0 == archive_read_next_header(a, &entry)) { if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { archive_read_finish(a); close(bsdtar->fd); bsdtar_errc(bsdtar, 1, 0, "Cannot append to compressed archive."); } /* Keep going until we hit end-of-archive */ format = archive_format(a); } end_offset = archive_read_header_position(a); archive_read_finish(a); /* Re-open archive for writing */ a = archive_write_new(); archive_write_set_compression_none(a); /* * Set the format to be used for writing. To allow people to * extend empty files, we need to allow them to specify the format, * which opens the possibility that they will specify a format that * doesn't match the existing format. Hence, the following bit * of arcane ugliness. */ if (bsdtar->create_format != NULL) { /* If the user requested a format, use that, but ... */ archive_write_set_format_by_name(a, bsdtar->create_format); /* ... complain if it's not compatible. */ format &= ARCHIVE_FORMAT_BASE_MASK; if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK) && format != ARCHIVE_FORMAT_EMPTY) { bsdtar_errc(bsdtar, 1, 0, "Format %s is incompatible with the archive %s.", bsdtar->create_format, bsdtar->filename); } } else { /* * Just preserve the current format, with a little care * for formats that libarchive can't write. */ if (format == ARCHIVE_FORMAT_TAR_GNUTAR) /* TODO: When gtar supports pax, use pax restricted. */ format = ARCHIVE_FORMAT_TAR_USTAR; if (format == ARCHIVE_FORMAT_EMPTY) format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; archive_write_set_format(a, format); } lseek(bsdtar->fd, end_offset, SEEK_SET); /* XXX check return val XXX */ 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_fd(a, bsdtar->fd)) bsdtar_errc(bsdtar, 1, 0, archive_error_string(a)); write_archive(a, bsdtar); /* XXX check return val XXX */ close(bsdtar->fd); bsdtar->fd = -1; }
static int arxive_start_stream(arc_handle_t ar, int fd) { return archive_read_open_fd(ar, fd, ARC_BLOCKSIZE); }
/* * Main loop: open the zipfile, iterate over its contents and decide what * to do with each entry. */ static void unzip(const char *fn) { struct archive *a; struct archive_entry *e; int fd, ret; uintmax_t total_size, file_count, error_count; if (strcmp(fn, "-") == 0) fd = STDIN_FILENO; else if ((fd = open(fn, O_RDONLY)) < 0) error("%s", fn); if ((a = archive_read_new()) == NULL) error("archive_read_new failed"); ac(archive_read_support_format_zip(a)); ac(archive_read_open_fd(a, fd, 8192)); if (!zipinfo_mode) { if (!p_opt && !q_opt) printf("Archive: %s\n", fn); if (v_opt == 1) { printf(" Length Date Time Name\n"); printf(" -------- ---- ---- ----\n"); } else if (v_opt == 2) { printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); printf("-------- ------ ------- ----- ---- ---- ------ ----\n"); } } total_size = 0; file_count = 0; error_count = 0; for (;;) { ret = archive_read_next_header(a, &e); if (ret == ARCHIVE_EOF) break; ac(ret); if (!zipinfo_mode) { if (t_opt) error_count += test(a, e); else if (v_opt) list(a, e); else if (p_opt || c_opt) extract_stdout(a, e); else extract(a, e); } else { if (Z1_opt) list(a, e); } total_size += archive_entry_size(e); ++file_count; } if (zipinfo_mode) { if (v_opt == 1) { printf(" -------- -------\n"); printf(" %8ju %ju file%s\n", total_size, file_count, file_count != 1 ? "s" : ""); } else if (v_opt == 2) { printf("-------- ------- --- -------\n"); printf("%8ju %7ju 0%% %ju file%s\n", total_size, total_size, file_count, file_count != 1 ? "s" : ""); } } ac(archive_read_close(a)); (void)archive_read_finish(a); if (fd != STDIN_FILENO && close(fd) != 0) error("%s", fn); if (t_opt) { if (error_count > 0) { errorx("%d checksum error(s) found.", error_count); } else { printf("No errors detected in compressed data of %s.\n", fn); } } }
void tar_mode_u(struct bsdtar *bsdtar) { off_t end_offset; struct archive *a; struct archive_entry *entry; int format; struct archive_dir_entry *p; struct archive_dir archive_dir; bsdtar->archive_dir = &archive_dir; memset(&archive_dir, 0, sizeof(archive_dir)); format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; /* Sanity-test some arguments and the file. */ test_for_append(bsdtar); bsdtar->fd = open(bsdtar->filename, O_RDWR); if (bsdtar->fd < 0) bsdtar_errc(bsdtar, 1, errno, "Cannot open %s", bsdtar->filename); a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_tar(a); archive_read_support_format_gnutar(a); if (archive_read_open_fd(a, bsdtar->fd, bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { bsdtar_errc(bsdtar, 1, 0, "Can't open %s: %s", bsdtar->filename, archive_error_string(a)); } /* Build a list of all entries and their recorded mod times. */ while (0 == archive_read_next_header(a, &entry)) { if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { archive_read_finish(a); close(bsdtar->fd); bsdtar_errc(bsdtar, 1, 0, "Cannot append to compressed archive."); } add_dir_list(bsdtar, archive_entry_pathname(entry), archive_entry_mtime(entry), archive_entry_mtime_nsec(entry)); /* Record the last format determination we see */ format = archive_format(a); /* Keep going until we hit end-of-archive */ } end_offset = archive_read_header_position(a); archive_read_finish(a); /* Re-open archive for writing. */ a = archive_write_new(); archive_write_set_compression_none(a); /* * Set format to same one auto-detected above, except that * we don't write GNU tar format, so use ustar instead. */ if (format == ARCHIVE_FORMAT_TAR_GNUTAR) format = ARCHIVE_FORMAT_TAR_USTAR; archive_write_set_format(a, format); 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); lseek(bsdtar->fd, end_offset, SEEK_SET); ftruncate(bsdtar->fd, end_offset); 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_fd(a, bsdtar->fd)) bsdtar_errc(bsdtar, 1, 0, archive_error_string(a)); write_archive(a, bsdtar); close(bsdtar->fd); bsdtar->fd = -1; while (bsdtar->archive_dir->head != NULL) { p = bsdtar->archive_dir->head->next; free(bsdtar->archive_dir->head->name); free(bsdtar->archive_dir->head); bsdtar->archive_dir->head = p; } bsdtar->archive_dir->tail = NULL; }
/* * Same as 'c', except we only support tar or empty formats in * uncompressed files on disk. */ void tar_mode_r(struct bsdtar *bsdtar) { int64_t end_offset; int format; struct archive *a; struct archive_entry *entry; int r; /* Sanity-test some arguments and the file. */ test_for_append(bsdtar); format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; #if defined(__BORLANDC__) bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY); #else bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY, 0666); #endif if (bsdtar->fd < 0) lafe_errc(1, errno, "Cannot open %s", bsdtar->filename); a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_empty(a); archive_read_support_format_tar(a); archive_read_support_format_gnutar(a); set_reader_options(bsdtar, a); r = archive_read_open_fd(a, bsdtar->fd, 10240); if (r != ARCHIVE_OK) lafe_errc(1, archive_errno(a), "Can't read archive %s: %s", bsdtar->filename, archive_error_string(a)); while (0 == archive_read_next_header(a, &entry)) { if (archive_filter_code(a, 0) != ARCHIVE_FILTER_NONE) { archive_read_free(a); close(bsdtar->fd); lafe_errc(1, 0, "Cannot append to compressed archive."); } /* Keep going until we hit end-of-archive */ format = archive_format(a); } end_offset = archive_read_header_position(a); archive_read_free(a); /* Re-open archive for writing */ a = archive_write_new(); /* * Set the format to be used for writing. To allow people to * extend empty files, we need to allow them to specify the format, * which opens the possibility that they will specify a format that * doesn't match the existing format. Hence, the following bit * of arcane ugliness. */ if (cset_get_format(bsdtar->cset) != NULL) { /* If the user requested a format, use that, but ... */ archive_write_set_format_by_name(a, cset_get_format(bsdtar->cset)); /* ... complain if it's not compatible. */ format &= ARCHIVE_FORMAT_BASE_MASK; if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK) && format != ARCHIVE_FORMAT_EMPTY) { lafe_errc(1, 0, "Format %s is incompatible with the archive %s.", cset_get_format(bsdtar->cset), bsdtar->filename); } } else { /* * Just preserve the current format, with a little care * for formats that libarchive can't write. */ if (format == ARCHIVE_FORMAT_EMPTY) format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; archive_write_set_format(a, format); } if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) lafe_errc(1, errno, "Could not seek to archive end"); set_writer_options(bsdtar, a); if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) lafe_errc(1, 0, "%s", archive_error_string(a)); write_archive(a, bsdtar); /* XXX check return val XXX */ close(bsdtar->fd); bsdtar->fd = -1; }
int HIDDEN xbps_unpack_binary_pkg(struct xbps_handle *xhp, xbps_dictionary_t pkg_repod) { struct archive *ar = NULL; struct stat st; const char *pkgver; char *bpkg = NULL; int pkg_fd = -1, rv = 0; assert(xbps_object_type(pkg_repod) == XBPS_TYPE_DICTIONARY); xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgver", &pkgver); xbps_set_cb_state(xhp, XBPS_STATE_UNPACK, 0, pkgver, NULL); bpkg = xbps_repository_pkg_path(xhp, pkg_repod); if (bpkg == NULL) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, errno, pkgver, "%s: [unpack] cannot determine binary package " "file for `%s': %s", pkgver, bpkg, strerror(errno)); return errno; } if ((ar = archive_read_new()) == NULL) { free(bpkg); return ENOMEM; } /* * Enable support for tar format and gzip/bzip2/lzma compression methods. */ archive_read_support_compression_gzip(ar); archive_read_support_compression_bzip2(ar); archive_read_support_compression_xz(ar); archive_read_support_format_tar(ar); pkg_fd = open(bpkg, O_RDONLY|O_CLOEXEC); if (pkg_fd == -1) { rv = errno; xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to open binary package `%s': %s", pkgver, bpkg, strerror(rv)); goto out; } if (fstat(pkg_fd, &st) == -1) { rv = errno; xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to fstat binary package `%s': %s", pkgver, bpkg, strerror(rv)); goto out; } if (archive_read_open_fd(ar, pkg_fd, st.st_blksize) == ARCHIVE_FATAL) { rv = archive_errno(ar); xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to read binary package `%s': %s", pkgver, bpkg, strerror(rv)); goto out; } /* * Extract archive files. */ if ((rv = unpack_archive(xhp, pkg_repod, pkgver, bpkg, ar)) != 0) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to unpack files from archive: %s", pkgver, strerror(rv)); goto out; } /* * Set package state to unpacked. */ if ((rv = xbps_set_pkg_state_installed(xhp, pkgver, XBPS_PKG_STATE_UNPACKED)) != 0) { xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL, rv, pkgver, "%s: [unpack] failed to set state to unpacked: %s", pkgver, strerror(rv)); } out: if (pkg_fd != -1) close(pkg_fd); if (ar) archive_read_finish(ar); if (bpkg) free(bpkg); return rv; }
void tar_mode_u(struct bsdtar *bsdtar) { int64_t end_offset; struct archive *a; struct archive_entry *entry; int format; struct archive_dir_entry *p; struct archive_dir archive_dir; bsdtar->archive_dir = &archive_dir; memset(&archive_dir, 0, sizeof(archive_dir)); format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; /* Sanity-test some arguments and the file. */ test_for_append(bsdtar); bsdtar->fd = open(bsdtar->filename, O_RDWR | O_BINARY); if (bsdtar->fd < 0) lafe_errc(1, errno, "Cannot open %s", bsdtar->filename); a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_tar(a); archive_read_support_format_gnutar(a); set_reader_options(bsdtar, a); if (archive_read_open_fd(a, bsdtar->fd, bsdtar->bytes_per_block) != ARCHIVE_OK) { lafe_errc(1, 0, "Can't open %s: %s", bsdtar->filename, archive_error_string(a)); } /* Build a list of all entries and their recorded mod times. */ while (0 == archive_read_next_header(a, &entry)) { if (archive_filter_code(a, 0) != ARCHIVE_FILTER_NONE) { archive_read_free(a); close(bsdtar->fd); lafe_errc(1, 0, "Cannot append to compressed archive."); } if (archive_match_exclude_entry(bsdtar->matching, ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER | ARCHIVE_MATCH_EQUAL, entry) != ARCHIVE_OK) lafe_errc(1, 0, "Error : %s", archive_error_string(bsdtar->matching)); /* Record the last format determination we see */ format = archive_format(a); /* Keep going until we hit end-of-archive */ } end_offset = archive_read_header_position(a); archive_read_free(a); /* Re-open archive for writing. */ a = archive_write_new(); /* * Set format to same one auto-detected above. */ archive_write_set_format(a, format); 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 (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0) lafe_errc(1, errno, "Could not seek to archive end"); set_writer_options(bsdtar, a); if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd)) lafe_errc(1, 0, "%s", archive_error_string(a)); write_archive(a, bsdtar); close(bsdtar->fd); bsdtar->fd = -1; while (bsdtar->archive_dir->head != NULL) { p = bsdtar->archive_dir->head->next; free(bsdtar->archive_dir->head->name); free(bsdtar->archive_dir->head); bsdtar->archive_dir->head = p; } bsdtar->archive_dir->tail = NULL; }
static int pkg_open_legacy(struct pkg **pkg_p, struct archive **a, struct archive_entry **ae, const char *path, struct pkg_manifest_key *keys, int flags, int fd) { struct pkg *pkg = NULL; pkg_error_t retcode = EPKG_OK; int ret; const char *fpath; bool manifest = false; bool read_from_stdin = 0; *a = archive_read_new(); archive_read_support_filter_all(*a); archive_read_support_format_tar(*a); /* archive_read_open_filename() treats a path of NULL as * meaning "read from stdin," but we want this behaviour if * path is exactly "-". In the unlikely event of wanting to * read an on-disk file called "-", just say "./-" or some * other leading path. */ if (fd == -1) { read_from_stdin = (strncmp(path, "-", 2) == 0); if (archive_read_open_filename(*a, read_from_stdin ? NULL : path, 4096) != ARCHIVE_OK) { if ((flags & PKG_OPEN_TRY) == 0) pkg_emit_error("archive_read_open_filename(%s): %s", path, archive_error_string(*a)); retcode = EPKG_FATAL; goto cleanup; } } else { if (archive_read_open_fd(*a, fd, 4096) != ARCHIVE_OK) { if ((flags & PKG_OPEN_TRY) == 0) pkg_emit_error("archive_read_open_fd: %s", archive_error_string(*a)); retcode = EPKG_FATAL; goto cleanup; } } retcode = pkg_new(pkg_p, PKG_FILE); if (retcode != EPKG_OK) goto cleanup; pkg = *pkg_p; while ((ret = archive_read_next_header(*a, ae)) == ARCHIVE_OK) { fpath = archive_entry_pathname(*ae); if (fpath[0] != '+') break; if (!manifest && (flags & PKG_OPEN_MANIFEST_COMPACT) && strcmp(fpath, "+COMPACT_MANIFEST") == 0) { char *buffer; manifest = true; size_t len = archive_entry_size(*ae); buffer = xmalloc(len); archive_read_data(*a, buffer, archive_entry_size(*ae)); ret = pkg_parse_manifest(pkg, buffer, len, keys); free(buffer); if (ret != EPKG_OK) { retcode = EPKG_FATAL; goto cleanup; } /* Do not read anything more */ break; } if (!manifest && strcmp(fpath, "+MANIFEST") == 0) { manifest = true; char *buffer; size_t len = archive_entry_size(*ae); buffer = xmalloc(len); archive_read_data(*a, buffer, archive_entry_size(*ae)); ret = pkg_parse_manifest(pkg, buffer, len, keys); free(buffer); if (ret != EPKG_OK) { if ((flags & PKG_OPEN_TRY) == 0) pkg_emit_error("%s is not a valid package: " "Invalid manifest", path); retcode = EPKG_FATAL; goto cleanup; } if (flags & PKG_OPEN_MANIFEST_ONLY) break; } } if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF) { if ((flags & PKG_OPEN_TRY) == 0) pkg_emit_error("archive_read_next_header(): %s", archive_error_string(*a)); retcode = EPKG_FATAL; } if (ret == ARCHIVE_EOF) retcode = EPKG_END; if (!manifest) { retcode = EPKG_FATAL; if ((flags & PKG_OPEN_TRY) == 0) pkg_emit_error("%s is not a valid package: no manifest found", path); } cleanup: if (retcode != EPKG_OK && retcode != EPKG_END) { if (*a != NULL) { archive_read_close(*a); archive_read_free(*a); } free(pkg); *pkg_p = NULL; *a = NULL; *ae = NULL; } return (retcode); }