static const char * packing_set_format(struct archive *a, pkg_formats format) { const char *notsupp_fmt = "%s is not supported, trying %s"; switch (format) { case TXZ: if (archive_write_set_compression_xz(a) == ARCHIVE_OK) return ("txz"); else pkg_emit_error(notsupp_fmt, "xz", "bzip2"); case TBZ: if (archive_write_set_compression_bzip2(a) == ARCHIVE_OK) return ("tbz"); else pkg_emit_error(notsupp_fmt, "bzip2", "gzip"); case TGZ: if (archive_write_set_compression_gzip(a) == ARCHIVE_OK) return ("tgz"); else pkg_emit_error(notsupp_fmt, "gzip", "plain tar"); case TAR: archive_write_set_compression_none(a); return ("tar"); } return (NULL); }
static const char * packing_set_format(struct archive *a, pkg_formats format) { switch (format) { case TXZ: if (archive_write_set_compression_xz(a) == ARCHIVE_OK) { return ("txz"); } else { pkg_emit_event(PKG_EVENT_ARCHIVE_COMP_UNSUP, /*argc*/2, "xz", "bzip2"); } case TBZ: if (archive_write_set_compression_bzip2(a) == ARCHIVE_OK) { return ("tbz"); } else { pkg_emit_event(PKG_EVENT_ARCHIVE_COMP_UNSUP, /*argc*/2, "bzip2", "gzip"); } case TGZ: if (archive_write_set_compression_gzip(a) == ARCHIVE_OK) { return ("tgz"); } else { pkg_emit_event(PKG_EVENT_ARCHIVE_COMP_UNSUP, /*argc*/2, "gzip", "plain tar"); } case TAR: archive_write_set_compression_none(a); return ("tar"); } return (NULL); }
/* * Initialize archive structure and create a shar archive. */ static struct archive * shar_create(void) { struct archive *a; if ((a = archive_write_new()) == NULL) errx(EXIT_FAILURE, "%s", archive_error_string(a)); if (b_opt) archive_write_set_format_shar_dump(a); else archive_write_set_format_shar(a); archive_write_set_compression_none(a); if (archive_write_open_filename(a, o_arg) != ARCHIVE_OK) errx(EX_CANTCREAT, "%s", archive_error_string(a)); return (a); }
/* * Allocate, initialize and return an archive object. */ struct archive * archive_write_new(void) { struct archive_write *a; unsigned char *nulls; a = (struct archive_write *)malloc(sizeof(*a)); if (a == NULL) return (NULL); memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_WRITE_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; a->archive.vtable = archive_write_vtable(); /* * The value 10240 here matches the traditional tar default, * but is otherwise arbitrary. * TODO: Set the default block size from the format selected. */ a->bytes_per_block = 10240; a->bytes_in_last_block = -1; /* Default */ /* Initialize a block of nulls for padding purposes. */ a->null_length = 1024; nulls = (unsigned char *)malloc(a->null_length); if (nulls == NULL) { free(a); return (NULL); } memset(nulls, 0, a->null_length); a->nulls = nulls; /* * Set default compression, but don't set a default format. * Were we to set a default format here, we would force every * client to link in support for that format, even if they didn't * ever use it. */ archive_write_set_compression_none(&a->archive); return (&a->archive); }
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; int separator = 0; int i = 0; if (prefix != NULL) { strcpy(filename, prefix); i = (int)strlen(prefix); } if (dlen > 0) { for (; i < dlen; i++) filename[i] = 'a'; filename[i++] = '/'; separator = 1; } for (; i < dlen + flen + separator; i++) filename[i] = 'b'; filename[i] = '\0'; strcpy(dirname, filename); /* Create a new archive in memory. */ assert((a = archive_write_new()) != NULL); assertA(0 == archive_write_set_format_ustar(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("dlen=%d, flen=%d", dlen, flen); if (flen > 100) { assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae)); } else { assertEqualIntA(a, 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("dlen=%d, flen=%d", dlen, flen); if (flen >= 100) { assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae)); } else { assertEqualIntA(a, 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("dlen=%d, flen=%d", dlen, flen); if (flen >= 100) { assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae)); } else { assertEqualIntA(a, 0, archive_write_header(a, ae)); } archive_entry_free(ae); /* Close out the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* * Now, read the data back. */ assert((a = archive_read_new()) != NULL); assertA(0 == archive_read_support_format_all(a)); assertA(0 == archive_read_support_filter_all(a)); assertA(0 == archive_read_open_memory(a, buff, used)); if (flen <= 100) { /* Read the file and check the filename. */ assertA(0 == archive_read_next_header(a, &ae)); failure("dlen=%d, flen=%d", dlen, flen); assertEqualString(filename, archive_entry_pathname(ae)); 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. */ if (flen <= 99) { assertA(0 == archive_read_next_header(a, &ae)); assert((S_IFDIR | 0755) == archive_entry_mode(ae)); failure("dlen=%d, flen=%d", dlen, flen); assertEqualString(dirname, archive_entry_pathname(ae)); } if (flen <= 99) { assertA(0 == archive_read_next_header(a, &ae)); assert((S_IFDIR | 0755) == archive_entry_mode(ae)); assertEqualString(dirname, archive_entry_pathname(ae)); } /* Verify the end of the archive. */ failure("This fails if entries were written that should not have been written. dlen=%d, flen=%d", dlen, flen); assertEqualInt(1, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
static void test_open_filename_mbs(void) { char buff[64]; struct archive_entry *ae; struct archive *a; /* Write an archive through this FILE *. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_compression_none(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_open_filename(a, "test.tar")); /* * Write a file to it. */ assert((ae = archive_entry_new()) != NULL); archive_entry_set_mtime(ae, 1, 0); archive_entry_copy_pathname(ae, "file"); archive_entry_set_mode(ae, S_IFREG | 0755); archive_entry_set_size(ae, 8); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); archive_entry_free(ae); assertEqualIntA(a, 8, archive_write_data(a, "12345678", 9)); /* * Write a second file to it. */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "file2"); archive_entry_set_mode(ae, S_IFREG | 0755); archive_entry_set_size(ae, 819200); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); archive_entry_free(ae); /* Close out the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* * Now, read the data back. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, "test.tar", 512)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualInt(1, archive_entry_mtime(ae)); assertEqualInt(0, archive_entry_mtime_nsec(ae)); assertEqualInt(0, archive_entry_atime(ae)); assertEqualInt(0, archive_entry_ctime(ae)); assertEqualString("file", archive_entry_pathname(ae)); assert((S_IFREG | 0755) == archive_entry_mode(ae)); assertEqualInt(8, archive_entry_size(ae)); assertEqualIntA(a, 8, archive_read_data(a, buff, 10)); assertEqualMem(buff, "12345678", 8); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("file2", archive_entry_pathname(ae)); assert((S_IFREG | 0755) == archive_entry_mode(ae)); assertEqualInt(819200, archive_entry_size(ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a)); /* Verify the end of the archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); /* * Verify some of the error handling. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_FATAL, archive_read_open_filename(a, "nonexistent.tar", 512)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
/* * Create an entry starting from a wide-character Unicode pathname, * read it back into "C" locale, which doesn't support the name. * TODO: Figure out the "right" behavior here. */ static void test_pax_filename_encoding_3(void) { wchar_t badname[] = L"xxxAyyyBzzz"; const char badname_utf8[] = "xxx\xE1\x88\xB4yyy\xE5\x99\xB8zzz"; struct archive *a; struct archive_entry *entry; char buff[65536]; size_t used; badname[3] = 0x1234; badname[7] = 0x5678; /* If it doesn't exist, just warn and return. */ if (NULL == setlocale(LC_ALL, "C")) { skipping("Can't set \"C\" locale, so can't exercise " "certain character-conversion failures"); return; } /* If wctomb is broken, warn and return. */ if (wctomb(buff, 0x1234) > 0) { skipping("Cannot test conversion failures because \"C\" " "locale on this system has no invalid characters."); return; } /* If wctomb is broken, warn and return. */ if (wctomb(buff, 0x1234) > 0) { skipping("Cannot test conversion failures because \"C\" " "locale on this system has no invalid characters."); return; } /* Skip test if archive_entry_update_pathname_utf8() is broken. */ /* In particular, this is currently broken on Win32 because * setlocale() does not set the default encoding for CP_ACP. */ entry = archive_entry_new(); if (archive_entry_update_pathname_utf8(entry, badname_utf8)) { archive_entry_free(entry); skipping("Cannot test conversion failures."); return; } archive_entry_free(entry); assert((a = archive_write_new()) != NULL); assertEqualIntA(a, 0, archive_write_set_format_pax(a)); assertEqualIntA(a, 0, archive_write_set_compression_none(a)); assertEqualIntA(a, 0, archive_write_set_bytes_per_block(a, 0)); assertEqualInt(0, archive_write_open_memory(a, buff, sizeof(buff), &used)); assert((entry = archive_entry_new()) != NULL); /* Set pathname to non-convertible wide value. */ archive_entry_copy_pathname_w(entry, badname); archive_entry_set_filetype(entry, AE_IFREG); assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry)); archive_entry_free(entry); assert((entry = archive_entry_new()) != NULL); archive_entry_copy_pathname_w(entry, L"abc"); /* Set gname to non-convertible wide value. */ archive_entry_copy_gname_w(entry, badname); archive_entry_set_filetype(entry, AE_IFREG); assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry)); archive_entry_free(entry); assert((entry = archive_entry_new()) != NULL); archive_entry_copy_pathname_w(entry, L"abc"); /* Set uname to non-convertible wide value. */ archive_entry_copy_uname_w(entry, badname); archive_entry_set_filetype(entry, AE_IFREG); assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry)); archive_entry_free(entry); assert((entry = archive_entry_new()) != NULL); archive_entry_copy_pathname_w(entry, L"abc"); /* Set hardlink to non-convertible wide value. */ archive_entry_copy_hardlink_w(entry, badname); archive_entry_set_filetype(entry, AE_IFREG); assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry)); archive_entry_free(entry); assert((entry = archive_entry_new()) != NULL); archive_entry_copy_pathname_w(entry, L"abc"); /* Set symlink to non-convertible wide value. */ archive_entry_copy_symlink_w(entry, badname); archive_entry_set_filetype(entry, AE_IFLNK); assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry)); archive_entry_free(entry); assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* * Now read the entries back. */ assert((a = archive_read_new()) != NULL); assertEqualInt(0, archive_read_support_format_tar(a)); assertEqualInt(0, archive_read_open_memory(a, buff, used)); failure("A non-convertible pathname should cause a warning."); assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry)); assertEqualWString(badname, archive_entry_pathname_w(entry)); failure("If native locale can't convert, we should get UTF-8 back."); assertEqualString(badname_utf8, archive_entry_pathname(entry)); failure("A non-convertible gname should cause a warning."); assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry)); assertEqualWString(badname, archive_entry_gname_w(entry)); failure("If native locale can't convert, we should get UTF-8 back."); assertEqualString(badname_utf8, archive_entry_gname(entry)); failure("A non-convertible uname should cause a warning."); assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry)); assertEqualWString(badname, archive_entry_uname_w(entry)); failure("If native locale can't convert, we should get UTF-8 back."); assertEqualString(badname_utf8, archive_entry_uname(entry)); failure("A non-convertible hardlink should cause a warning."); assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry)); assertEqualWString(badname, archive_entry_hardlink_w(entry)); failure("If native locale can't convert, we should get UTF-8 back."); assertEqualString(badname_utf8, archive_entry_hardlink(entry)); failure("A non-convertible symlink should cause a warning."); assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry)); assertEqualWString(badname, archive_entry_symlink_w(entry)); assertEqualWString(NULL, archive_entry_hardlink_w(entry)); failure("If native locale can't convert, we should get UTF-8 back."); assertEqualString(badname_utf8, archive_entry_symlink(entry)); assertEqualInt(ARCHIVE_EOF, archive_read_next_header(a, &entry)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
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); }
/* * 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; }
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); }
static void test_format(int (*set_format)(struct archive *)) { char filedata[64]; struct archive_entry *ae; struct archive *a; char *p; size_t used; size_t buffsize = 1000000; char *buff; int damaged = 0; buff = malloc(buffsize); /* Create a new archive in memory. */ assert((a = archive_write_new()) != NULL); assertA(0 == (*set_format)(a)); assertA(0 == archive_write_set_compression_none(a)); assertA(0 == archive_write_open_memory(a, buff, buffsize, &used)); /* * Write a file to it. */ assert((ae = archive_entry_new()) != NULL); archive_entry_set_mtime(ae, 1, 10); assert(1 == archive_entry_mtime(ae)); assert(10 == archive_entry_mtime_nsec(ae)); p = strdup("file"); archive_entry_copy_pathname(ae, p); strcpy(p, "XXXX"); free(p); assertEqualString("file", archive_entry_pathname(ae)); archive_entry_set_mode(ae, S_IFREG | 0755); assert((S_IFREG | 0755) == archive_entry_mode(ae)); archive_entry_set_size(ae, 8); assertA(0 == archive_write_header(a, ae)); archive_entry_free(ae); assertA(8 == archive_write_data(a, "12345678", 9)); /* * Write another file to it. */ assert((ae = archive_entry_new()) != NULL); archive_entry_set_mtime(ae, 1, 10); assert(1 == archive_entry_mtime(ae)); assert(10 == archive_entry_mtime_nsec(ae)); p = strdup("file2"); archive_entry_copy_pathname(ae, p); strcpy(p, "XXXX"); free(p); assertEqualString("file2", archive_entry_pathname(ae)); archive_entry_set_mode(ae, S_IFREG | 0755); assert((S_IFREG | 0755) == archive_entry_mode(ae)); archive_entry_set_size(ae, 4); assertA(0 == archive_write_header(a, ae)); archive_entry_free(ae); assertA(4 == archive_write_data(a, "1234", 5)); /* * Write a directory to it. */ assert((ae = archive_entry_new()) != NULL); archive_entry_set_mtime(ae, 11, 110); archive_entry_copy_pathname(ae, "dir"); archive_entry_set_mode(ae, S_IFDIR | 0755); archive_entry_set_size(ae, 512); assertA(0 == archive_write_header(a, ae)); assertEqualInt(0, archive_entry_size(ae)); archive_entry_free(ae); assertEqualIntA(a, 0, archive_write_data(a, "12345678", 9)); /* 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 /* * Damage the second entry to test the search-ahead recovery. * TODO: Move the damage-recovery checking to a separate test; * it doesn't really belong in this write test. */ { int i; for (i = 80; i < 150; i++) { if (memcmp(buff + i, "07070", 5) == 0) { damaged = 1; buff[i] = 'X'; break; } } } failure("Unable to locate the second header for damage-recovery test."); assert(damaged == 1); /* * 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)); if (!assertEqualIntA(a, 0, archive_read_next_header(a, &ae))) { archive_read_finish(a); return; } assertEqualInt(1, archive_entry_mtime(ae)); /* Not the same as above: cpio doesn't store hi-res times. */ assert(0 == archive_entry_mtime_nsec(ae)); assert(0 == archive_entry_atime(ae)); assert(0 == archive_entry_ctime(ae)); assertEqualString("file", archive_entry_pathname(ae)); assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae)); assertEqualInt(8, archive_entry_size(ae)); assertA(8 == archive_read_data(a, filedata, 10)); assert(0 == memcmp(filedata, "12345678", 8)); /* * The second file can't be read because we damaged its header. */ /* * Read the dir entry back. * ARCHIVE_WARN here because the damaged entry was skipped. */ assertEqualIntA(a, ARCHIVE_WARN, archive_read_next_header(a, &ae)); assertEqualInt(11, archive_entry_mtime(ae)); assert(0 == archive_entry_mtime_nsec(ae)); assert(0 == archive_entry_atime(ae)); assert(0 == archive_entry_ctime(ae)); assertEqualString("dir", archive_entry_pathname(ae)); assertEqualInt((S_IFDIR | 0755), archive_entry_mode(ae)); assertEqualInt(0, archive_entry_size(ae)); assertEqualIntA(a, 0, archive_read_data(a, filedata, 10)); /* Verify the end of the archive. */ assertEqualIntA(a, 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 free(buff); }
const gchar* archive_create(const char* archive_name, GSList* files, COMPRESS_METHOD method, ARCHIVE_FORMAT format) { struct archive* arch; struct archive_entry* entry; char* buf = NULL; ssize_t len; int fd; struct stat st; struct file_info* file; gchar* filename = NULL; gchar* msg = NULL; #ifndef _TEST gint num = 0; gint total = g_slist_length (files); #endif g_return_val_if_fail(files != NULL, "No files for archiving"); debug_print("File: %s\n", archive_name); arch = archive_write_new(); switch (method) { case ZIP: if (archive_write_set_compression_gzip(arch) != ARCHIVE_OK) return archive_error_string(arch); break; case BZIP2: if (archive_write_set_compression_bzip2(arch) != ARCHIVE_OK) return archive_error_string(arch); break; #if NEW_ARCHIVE_API case COMPRESS: if (archive_write_set_compression_compress(arch) != ARCHIVE_OK) return archive_error_string(arch); break; #endif case NO_COMPRESS: if (archive_write_set_compression_none(arch) != ARCHIVE_OK) return archive_error_string(arch); break; } switch (format) { case TAR: if (archive_write_set_format_ustar(arch) != ARCHIVE_OK) return archive_error_string(arch); break; case SHAR: if (archive_write_set_format_shar(arch) != ARCHIVE_OK) return archive_error_string(arch); break; case PAX: if (archive_write_set_format_pax(arch) != ARCHIVE_OK) return archive_error_string(arch); break; case CPIO: if (archive_write_set_format_cpio(arch) != ARCHIVE_OK) return archive_error_string(arch); break; case NO_FORMAT: return "Missing archive format"; } if (archive_write_open_file(arch, archive_name) != ARCHIVE_OK) return archive_error_string(arch); while (files && ! stop_action) { #ifndef _TEST set_progress_print_all(num++, total, 30); #endif file = (struct file_info *) files->data; if (!file) continue; filename = get_full_path(file); /* libarchive will crash if instructed to add archive to it self */ if (g_utf8_collate(archive_name, filename) == 0) { buf = NULL; buf = g_strdup_printf( "%s: Not dumping to %s", archive_name, filename); g_warning("%s\n", buf); #ifndef _TEST debug_print("%s\n", buf); #endif g_free(buf); } else { #ifndef _TEST debug_print("Adding: %s\n", filename); msg = g_strdup_printf("%s", filename); set_progress_file_label(msg); g_free(msg); #endif entry = archive_entry_new(); lstat(filename, &st); if ((fd = open(filename, O_RDONLY)) == -1) { perror("open file"); } else { archive_entry_copy_stat(entry, &st); archive_entry_set_pathname(entry, filename); if (S_ISLNK(st.st_mode)) { buf = NULL; buf = malloc(PATH_MAX + 1); if ((len = readlink(filename, buf, PATH_MAX)) < 0) perror("error in readlink"); else buf[len] = '\0'; archive_entry_set_symlink(entry, buf); g_free(buf); archive_entry_set_size(entry, 0); archive_write_header(arch, entry); } else { if (archive_write_header(arch, entry) != ARCHIVE_OK) g_warning("%s", archive_error_string(arch)); buf = NULL; buf = malloc(READ_BLOCK_SIZE); len = read(fd, buf, READ_BLOCK_SIZE); while (len > 0) { if (archive_write_data(arch, buf, len) == -1) g_warning("%s", archive_error_string(arch)); memset(buf, 0, READ_BLOCK_SIZE); len = read(fd, buf, READ_BLOCK_SIZE); } g_free(buf); } close(fd); archive_entry_free(entry); } } g_free(filename); files = g_slist_next(files); } #ifndef _TEST if (stop_action) unlink(archive_name); stop_action = FALSE; #endif archive_write_close(arch); archive_write_finish(arch); return NULL; }
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); }
/* * Set the locale and write a pathname containing invalid characters. * This should work; the underlying implementation should automatically * fall back to storing the pathname in binary. */ static void test_pax_filename_encoding_2(void) { char filename[] = "abc\314\214mno\374xyz"; struct archive *a; struct archive_entry *entry; char buff[65536]; char longname[] = "abc\314\214mno\374xyz" "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz" "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz" "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz" "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz" "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz" "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz" ; size_t used; /* * We need a starting locale which has invalid sequences. * en_US.UTF-8 seems to be commonly supported. */ /* If it doesn't exist, just warn and return. */ if (NULL == setlocale(LC_ALL, "en_US.UTF-8")) { skipping("invalid encoding tests require a suitable locale;" " en_US.UTF-8 not available on this system"); return; } assert((a = archive_write_new()) != NULL); assertEqualIntA(a, 0, archive_write_set_format_pax(a)); assertEqualIntA(a, 0, archive_write_set_compression_none(a)); assertEqualIntA(a, 0, archive_write_set_bytes_per_block(a, 0)); assertEqualInt(0, archive_write_open_memory(a, buff, sizeof(buff), &used)); assert((entry = archive_entry_new()) != NULL); /* Set pathname, gname, uname, hardlink to nonconvertible values. */ archive_entry_copy_pathname(entry, filename); archive_entry_copy_gname(entry, filename); archive_entry_copy_uname(entry, filename); archive_entry_copy_hardlink(entry, filename); archive_entry_set_filetype(entry, AE_IFREG); failure("This should generate a warning for nonconvertible names."); assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry)); archive_entry_free(entry); assert((entry = archive_entry_new()) != NULL); /* Set path, gname, uname, and symlink to nonconvertible values. */ archive_entry_copy_pathname(entry, filename); archive_entry_copy_gname(entry, filename); archive_entry_copy_uname(entry, filename); archive_entry_copy_symlink(entry, filename); archive_entry_set_filetype(entry, AE_IFLNK); failure("This should generate a warning for nonconvertible names."); assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry)); archive_entry_free(entry); assert((entry = archive_entry_new()) != NULL); /* Set pathname to a very long nonconvertible value. */ archive_entry_copy_pathname(entry, longname); archive_entry_set_filetype(entry, AE_IFREG); failure("This should generate a warning for nonconvertible names."); assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry)); archive_entry_free(entry); assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* * Now read the entries back. */ assert((a = archive_read_new()) != NULL); assertEqualInt(0, archive_read_support_format_tar(a)); assertEqualInt(0, archive_read_open_memory(a, buff, used)); assertEqualInt(0, archive_read_next_header(a, &entry)); assertEqualString(filename, archive_entry_pathname(entry)); assertEqualString(filename, archive_entry_gname(entry)); assertEqualString(filename, archive_entry_uname(entry)); assertEqualString(filename, archive_entry_hardlink(entry)); assertEqualInt(0, archive_read_next_header(a, &entry)); assertEqualString(filename, archive_entry_pathname(entry)); assertEqualString(filename, archive_entry_gname(entry)); assertEqualString(filename, archive_entry_uname(entry)); assertEqualString(filename, archive_entry_symlink(entry)); assertEqualInt(0, archive_read_next_header(a, &entry)); assertEqualString(longname, archive_entry_pathname(entry)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
static void test_1(void) { struct archive_entry *ae; struct archive *a; size_t used; size_t blocksize; int64_t offset, length; char *buff2; size_t buff2_size = 0x13000; char buff3[1024]; long i; assert((buff2 = malloc(buff2_size)) != NULL); /* Repeat the following for a variety of odd blocksizes. */ for (blocksize = 1; blocksize < 100000; blocksize += blocksize + 3) { /* Create a new archive in memory. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_pax(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_compression_none(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, (int)blocksize)); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, (int)blocksize)); assertEqualInt(blocksize, archive_write_get_bytes_in_last_block(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, sizeof(buff), &used)); assertEqualInt(blocksize, archive_write_get_bytes_in_last_block(a)); /* * Write a file to it. */ assert((ae = archive_entry_new()) != NULL); archive_entry_set_mtime(ae, 1, 10); assertEqualInt(1, archive_entry_mtime(ae)); assertEqualInt(10, archive_entry_mtime_nsec(ae)); archive_entry_copy_pathname(ae, "file"); assertEqualString("file", archive_entry_pathname(ae)); archive_entry_set_mode(ae, S_IFREG | 0755); assertEqualInt(S_IFREG | 0755, archive_entry_mode(ae)); archive_entry_set_size(ae, 0x81000); archive_entry_sparse_add_entry(ae, 0x10000, 0x1000); archive_entry_sparse_add_entry(ae, 0x80000, 0x1000); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); archive_entry_free(ae); memset(buff2, 'a', buff2_size); for (i = 0; i < 0x81000;) { size_t ws = buff2_size; if (i + ws > 0x81000) ws = 0x81000 - i; assertEqualInt(ws, archive_write_data(a, buff2, ws)); i += ws; } /* Close out the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* This calculation gives "the smallest multiple of * the block size that is at least 11264 bytes". */ failure("blocksize=%d", blocksize); assertEqualInt(((11264 - 1)/blocksize+1)*blocksize, used); /* * Now, read the data back. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualInt(1, archive_entry_mtime(ae)); assertEqualInt(10, archive_entry_mtime_nsec(ae)); assertEqualInt(0, archive_entry_atime(ae)); assertEqualInt(0, archive_entry_ctime(ae)); assertEqualString("file", archive_entry_pathname(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(AE_IFREG | 0755, archive_entry_mode(ae)); assertEqualInt(0x81000, archive_entry_size(ae)); /* Verify sparse information. */ assertEqualInt(2, archive_entry_sparse_reset(ae)); assertEqualInt(0, archive_entry_sparse_next(ae, &offset, &length)); assertEqualInt(0x10000, offset); assertEqualInt(0x1000, length); assertEqualInt(0, archive_entry_sparse_next(ae, &offset, &length)); assertEqualInt(0x80000, offset); assertEqualInt(0x1000, length); /* Verify file contents. */ memset(buff3, 0, sizeof(buff3)); for (i = 0; i < 0x10000; i += 1024) { assertEqualInt(1024, archive_read_data(a, buff2, 1024)); failure("Read data(0x%lx - 0x%lx) should be all zero", i, i + 1024); assertEqualMem(buff2, buff3, 1024); } memset(buff3, 'a', sizeof(buff3)); for (i = 0x10000; i < 0x11000; i += 1024) { assertEqualInt(1024, archive_read_data(a, buff2, 1024)); failure("Read data(0x%lx - 0x%lx) should be all 'a'", i, i + 1024); assertEqualMem(buff2, buff3, 1024); } memset(buff3, 0, sizeof(buff3)); for (i = 0x11000; i < 0x80000; i += 1024) { assertEqualInt(1024, archive_read_data(a, buff2, 1024)); failure("Read data(0x%lx - 0x%lx) should be all zero", i, i + 1024); assertEqualMem(buff2, buff3, 1024); } memset(buff3, 'a', sizeof(buff3)); for (i = 0x80000; i < 0x81000; i += 1024) { assertEqualInt(1024, archive_read_data(a, buff2, 1024)); failure("Read data(0x%lx - 0x%lx) should be all 'a'", i, i + 1024); assertEqualMem(buff2, buff3, 1024); } /* Verify the end of the archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } free(buff2); }
void pkg_sign_gpg(const char *name, const char *output) { struct archive *pkg; struct archive_entry *entry, *hash_entry, *sign_entry; int fd; struct stat sb; char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; unsigned char block[65536]; off_t i, size; size_t block_len, signature_len; if ((fd = open(name, O_RDONLY)) == -1) err(EXIT_FAILURE, "Cannot open binary package %s", name); if (fstat(fd, &sb) == -1) err(EXIT_FAILURE, "Cannot stat %s", name); entry = archive_entry_new(); archive_entry_copy_stat(entry, &sb); pkgname = extract_pkgname(fd); hash_file = xasprintf(hash_template, pkgname, (long long)archive_entry_size(entry)); free(pkgname); for (i = 0; i < archive_entry_size(entry); i += block_len) { if (i + (off_t)sizeof(block) < archive_entry_size(entry)) block_len = sizeof(block); else block_len = archive_entry_size(entry) % sizeof(block); if (read(fd, block, block_len) != (ssize_t)block_len) err(2, "short read"); hash_block(block, block_len, hash); tmp = xasprintf("%s%s\n", hash_file, hash); free(hash_file); hash_file = tmp; } tmp = xasprintf("%s%s", hash_file, hash_trailer); free(hash_file); hash_file = tmp; if (detached_gpg_sign(hash_file, strlen(hash_file), &signature_file, &signature_len, gpg_keyring_sign, gpg_sign_as)) err(EXIT_FAILURE, "Cannot sign hash file"); lseek(fd, 0, SEEK_SET); sign_entry = archive_entry_clone(entry); hash_entry = archive_entry_clone(entry); pkgname = strrchr(name, '/'); archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); archive_entry_set_pathname(hash_entry, HASH_FNAME); archive_entry_set_pathname(sign_entry, GPG_SIGNATURE_FNAME); archive_entry_set_size(hash_entry, strlen(hash_file)); archive_entry_set_size(sign_entry, signature_len); pkg = archive_write_new(); archive_write_set_compression_none(pkg); archive_write_set_format_ar_bsd(pkg); archive_write_open_filename(pkg, output); archive_write_header(pkg, hash_entry); archive_write_data(pkg, hash_file, strlen(hash_file)); archive_write_finish_entry(pkg); archive_entry_free(hash_entry); archive_write_header(pkg, sign_entry); archive_write_data(pkg, signature_file, signature_len); archive_write_finish_entry(pkg); archive_entry_free(sign_entry); size = archive_entry_size(entry); archive_write_header(pkg, entry); for (i = 0; i < size; i += block_len) { if (i + (off_t)sizeof(block) < size) block_len = sizeof(block); else block_len = size % sizeof(block); if (read(fd, block, block_len) != (ssize_t)block_len) err(2, "short read"); archive_write_data(pkg, block, block_len); } archive_write_finish_entry(pkg); archive_entry_free(entry); archive_write_finish(pkg); close(fd); exit(0); }
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; }
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); }
static void create(const char *filename, int compress, const char **argv) { struct archive *a; struct archive *disk; struct archive_entry *entry; ssize_t len; int fd; a = archive_write_new(); switch (compress) { #ifndef NO_BZIP2_CREATE case 'j': case 'y': archive_write_set_compression_bzip2(a); break; #endif #ifndef NO_COMPRESS_CREATE case 'Z': archive_write_set_compression_compress(a); break; #endif #ifndef NO_GZIP_CREATE case 'z': archive_write_set_compression_gzip(a); break; #endif default: archive_write_set_compression_none(a); break; } archive_write_set_format_ustar(a); if (strcmp(filename, "-") == 0) filename = NULL; archive_write_open_file(a, filename); disk = archive_read_disk_new(); #ifndef NO_LOOKUP archive_read_disk_set_standard_lookup(disk); #endif while (*argv != NULL) { struct tree *t = tree_open(*argv); while (tree_next(t)) { entry = archive_entry_new(); archive_entry_set_pathname(entry, tree_current_path(t)); archive_read_disk_entry_from_file(disk, entry, -1, tree_current_stat(t)); if (verbose) { msg("a "); msg(tree_current_path(t)); } archive_write_header(a, entry); fd = open(tree_current_access_path(t), 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); if (verbose) msg("\n"); } argv++; } archive_write_close(a); archive_write_finish(a); }
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 }
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; } } } }