void DTAR_writer_init() { char compress=DTAR_user_opts->compress; char filename=DTAR_user_opts->dest_path; DTAR_writer->flags= O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC; DTAR_writer->a=archive_write_new(); switch (compress) { case 'j': case 'y': archive_write_add_filter_bzip2(a); break; case 'Z': archive_write_add_filter_compress(a); break; case 'z': archive_write_add_filter_gzip(a); break; default: archive_write_add_filter_none(a); break; } archive_write_set_format_ustar(a); archive_write_set_bytes_per_block(a,0); if (strcmp(filename, "-") == 0) filename = NULL; DTAR_writer->fd_tar=open(filename,DTAR_writer->flags,0666); archive_write_open_fd(a, DTAR_writer->fd_tar); }
void tar_mode_c(struct bsdtar *bsdtar) { struct archive *a; const void *filter_name; int r; if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) lafe_errc(1, 0, "no files or directories specified"); a = archive_write_new(); /* Support any format that the library supports. */ if (cset_get_format(bsdtar->cset) == NULL) { r = archive_write_set_format_pax_restricted(a); cset_set_format(bsdtar->cset, "pax restricted"); } else { r = archive_write_set_format_by_name(a, cset_get_format(bsdtar->cset)); } if (r != ARCHIVE_OK) { fprintf(stderr, "Can't use format %s: %s\n", cset_get_format(bsdtar->cset), archive_error_string(a)); usage(); } archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); r = cset_write_add_filters(bsdtar->cset, a, &filter_name); if (r < ARCHIVE_WARN) { lafe_errc(1, 0, "Unsupported compression option --%s", (const char *)filter_name); } set_writer_options(bsdtar, a); if (bsdtar->passphrase != NULL) r = archive_write_set_passphrase(a, bsdtar->passphrase); else r = archive_write_set_passphrase_callback(a, bsdtar, &passphrase_callback); if (r != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(a)); if (ARCHIVE_OK != archive_write_open_filename(a, bsdtar->filename)) lafe_errc(1, 0, "%s", archive_error_string(a)); write_archive(a, bsdtar); }
/* * Archiving related functions. * This one creates a list of files to be included into the archive and * sets up the libarchive context. */ int setup_archiver(pc_ctx_t *pctx, struct stat *sbuf) { char *tmpfile, *tmp; int err, fd; uchar_t *pbuf; struct archive *arc; struct fn_list *fn; /* * If sorting is enabled create the initial sort buffer. */ if (pctx->enable_archive_sort) { struct sort_buf *srt; srt = (struct sort_buf *)malloc(sizeof (struct sort_buf)); if (srt == NULL) { log_msg(LOG_ERR, 0, "Out of memory."); return (-1); } srt->next = NULL; srt->pos = 0; pctx->archive_sort_buf = srt; } /* * Create a temporary file to hold the generated list of pathnames to be archived. * Storing in a file saves memory usage and allows scalability. */ tmpfile = pctx->archive_members_file; tmp = get_temp_dir(); strcpy(tmpfile, tmp); free(tmp); strcat(tmpfile, "/.pcompXXXXXX"); if ((fd = mkstemp(tmpfile)) == -1) { log_msg(LOG_ERR, 1, "mkstemp errored."); return (-1); } add_fname(tmpfile); pbuf = malloc(pctx->chunksize); if (pbuf == NULL) { log_msg(LOG_ERR, 0, "Out of memory."); close(fd); unlink(tmpfile); return (-1); } /* * Use nftw() to scan all the directory hierarchies provided on the command * line and generate a consolidated list of pathnames to be archived. By * doing this we can sort the pathnames and estimate the total archive size. * Total archive size is needed by the subsequent compression stages. */ log_msg(LOG_INFO, 0, "Scanning files."); sbuf->st_size = 0; pctx->archive_size = 0; pctx->archive_members_count = 0; /* * nftw requires using global state variable. So we lock to be mt-safe. * This means only one directory tree scan can happen at a time. */ pthread_mutex_lock(&nftw_mutex); fn = pctx->fn; a_state.pbuf = pbuf; a_state.bufsiz = pctx->chunksize; a_state.bufpos = 0; a_state.fd = fd; a_state.srt = pctx->archive_sort_buf; a_state.srt_pos = 0; a_state.head = a_state.srt; a_state.pathlist_size = 0; while (fn) { struct stat sb; if (lstat(fn->filename, &sb) == -1) { log_msg(LOG_ERR, 1, "Ignoring %s.", fn->filename); fn = fn->next; continue; } a_state.arc_size = 0; a_state.fcount = 0; if (S_ISDIR(sb.st_mode)) { /* * Depth-First scan, FTW_DEPTH, is needed to handle restoring * all directory permissions correctly. */ err = nftw(fn->filename, add_pathname, 1024, FTW_PHYS | FTW_DEPTH); } else { int tflag; struct FTW ftwbuf; char *pos; if (S_ISLNK(sb.st_mode)) tflag = FTW_SL; else tflag = FTW_F; /* * Find out basename to mimic FTW. */ pos = strrchr(fn->filename, PATHSEP_CHAR); if (pos) ftwbuf.base = pos - fn->filename + 1; else ftwbuf.base = 0; add_pathname(fn->filename, &sb, tflag, &ftwbuf); a_state.arc_size = sb.st_size; } if (a_state.bufpos > 0) { ssize_t wrtn = Write(a_state.fd, a_state.pbuf, a_state.bufpos); if (wrtn < a_state.bufpos) { log_msg(LOG_ERR, 1, "Write failed."); close(fd); unlink(tmpfile); return (-1); } a_state.bufpos = 0; a_state.pathlist_size += wrtn; } pctx->archive_size += a_state.arc_size; pctx->archive_members_count += a_state.fcount; fn = fn->next; } if (a_state.srt == NULL) { pctx->enable_archive_sort = 0; } else { log_msg(LOG_INFO, 0, "Sorting ..."); a_state.srt->max = a_state.srt_pos - 1; qsort(a_state.srt->members, a_state.srt_pos, sizeof (member_entry_t), compare_members); pctx->archive_temp_size = a_state.pathlist_size; } pthread_mutex_unlock(&nftw_mutex); sbuf->st_size = pctx->archive_size; lseek(fd, 0, SEEK_SET); free(pbuf); sbuf->st_uid = geteuid(); sbuf->st_gid = getegid(); sbuf->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; arc = archive_write_new(); if (!arc) { log_msg(LOG_ERR, 1, "Unable to create libarchive context.\n"); close(fd); unlink(tmpfile); return (-1); } archive_write_set_format_pax_restricted(arc); archive_write_set_bytes_per_block(arc, 0); archive_write_open(arc, pctx, arc_open_callback, creat_write_callback, creat_close_callback); pctx->archive_ctx = arc; pctx->archive_members_fd = fd; if (pctx->enable_archive_sort) { pctx->temp_mmap_len = TEMP_MMAP_SIZE; pctx->temp_mmap_buf = mmap(NULL, pctx->temp_mmap_len, PROT_READ, MAP_SHARED, pctx->archive_members_fd, 0); if (pctx->temp_mmap_buf == NULL) { log_msg(LOG_WARN, 1, "Unable to mmap pathlist file, switching to read()."); pctx->temp_mmap_len = 0; } } else { pctx->temp_mmap_buf = NULL; pctx->temp_mmap_len = 0; } pctx->temp_mmap_pos = 0; pctx->arc_writing = 0; return (0); }
/*! * \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_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); }
////////////////////////////////////////////////////////////////////// // Constructor: static int ar_write(lua_State *L) { struct archive** self_ref; static struct { const char *name; int (*setter)(struct archive *); } names[] = { /* Copied from archive_write_set_format_by_name.c */ { "ar", archive_write_set_format_ar_bsd }, { "arbsd", archive_write_set_format_ar_bsd }, { "argnu", archive_write_set_format_ar_svr4 }, { "arsvr4", archive_write_set_format_ar_svr4 }, { "cpio", archive_write_set_format_cpio }, { "mtree", archive_write_set_format_mtree }, { "newc", archive_write_set_format_cpio_newc }, { "odc", archive_write_set_format_cpio }, { "pax", archive_write_set_format_pax }, { "posix", archive_write_set_format_pax }, { "shar", archive_write_set_format_shar }, { "shardump", archive_write_set_format_shar_dump }, { "ustar", archive_write_set_format_ustar }, /* New ones to more closely match the C API */ { "ar_bsd", archive_write_set_format_ar_bsd }, { "ar_svr4", archive_write_set_format_ar_svr4 }, { "cpio_newc", archive_write_set_format_cpio_newc }, { "pax_restricted", archive_write_set_format_pax_restricted }, { "shar_dump", archive_write_set_format_shar_dump }, { NULL, NULL } }; int idx = 0; const char* name; luaL_checktype(L, 1, LUA_TTABLE); self_ref = (struct archive**) lua_newuserdata(L, sizeof(struct archive*)); // {ud} luaL_getmetatable(L, AR_WRITE); // {ud}, [write] lua_setmetatable(L, -2); // {ud} __ref_count++; *self_ref = archive_write_new(); // Register it in the weak metatable: ar_registry_set(L, *self_ref); // Create an environment to store a reference to the writer: lua_createtable(L, 1, 0); // {ud}, {} lua_pushliteral(L, "writer"); // {ud}, {}, "writer" lua_rawget(L, 1); // {ud}, {}, fn if ( ! lua_isfunction(L, -1) ) { err("MissingArgument: required parameter 'writer' must be a function"); } lua_setfield(L, -2, "writer"); lua_setfenv(L, -2); // {ud} // Extract various fields and prepare the archive: lua_getfield(L, 1, "bytes_per_block"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_write_set_bytes_per_block(*self_ref, lua_tointeger(L, -1)) ) { err("archive_write_set_bytes_per_block: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); lua_getfield(L, 1, "bytes_in_last_block"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_write_set_bytes_in_last_block(*self_ref, lua_tointeger(L, -1)) ) { err("archive_write_set_bytes_in_last_block: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); lua_getfield(L, 1, "skip_file"); if ( ! lua_isnil(L, -1) ) { dev_t dev; ino_t ino; if ( LUA_TTABLE != lua_type(L, -1) ) { err("skip_file member must be a table object"); } lua_getfield(L, -1, "dev"); if ( ! lua_isnumber(L, -1) ) { err("skip_file.dev member must be a number"); } dev = (dev_t)lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, -1, "ino"); if ( ! lua_isnumber(L, -1) ) { err("skip_file.ino member must be a number"); } ino = (ino_t)lua_tonumber(L, -1); lua_pop(L, 1); if ( ARCHIVE_OK != archive_write_set_skip_file(*self_ref, dev, ino) ) { err("archive_write_set_skip_file: %s", archive_error_string(*self_ref)); } } lua_pop(L, 1); lua_getfield(L, 1, "format"); if ( lua_isnil(L, -1) ) { lua_pop(L, 1); lua_pushliteral(L, "posix"); } name = lua_tostring(L, -1); for ( ;; idx++ ) { if ( names[idx].name == NULL ) { err("archive_write_set_format_*: No such format '%s'", name); } if ( strcmp(name, names[idx].name) == 0 ) break; } if ( ARCHIVE_OK != (names[idx].setter)(*self_ref) ) { err("archive_write_set_format_%s: %s", name, archive_error_string(*self_ref)); } lua_pop(L, 1); lua_getfield(L, 1, "compression"); if ( ! lua_isnil(L, -1) ) { static struct { const char *name; int (*setter)(struct archive *); } names[] = { { "bzip2", archive_write_add_filter_bzip2 }, { "compress", archive_write_add_filter_compress }, { "gzip", archive_write_add_filter_gzip }, { "lzma", archive_write_add_filter_lzma }, { "xz", archive_write_add_filter_xz }, { NULL, NULL } }; int idx = 0; const char* name = lua_tostring(L, -1); for ( ;; idx++ ) { if ( names[idx].name == NULL ) { err("archive_write_set_compression_*: No such compression '%s'", name); } if ( strcmp(name, names[idx].name) == 0 ) break; } if ( ARCHIVE_OK != (names[idx].setter)(*self_ref) ) { err("archive_write_set_compression_%s: %s", name, archive_error_string(*self_ref)); } } lua_pop(L, 1); lua_getfield(L, 1, "options"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_write_set_options(*self_ref, lua_tostring(L, -1)) ) { err("archive_write_set_options: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); if ( ARCHIVE_OK != archive_write_open(*self_ref, L, NULL, &ar_write_cb, NULL) ) { err("archive_write_open: %s", archive_error_string(*self_ref)); } return 1; }
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 }
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; }
void tarsnap_mode_c(struct bsdtar *bsdtar) { struct archive *a; size_t i; if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) bsdtar_errc(bsdtar, 1, 0, "no files or directories specified"); for (i = 0; bsdtar->argv[i] != NULL; i++) { if (bsdtar->argv[i][0] == '-' && bsdtar->argv[i][1] == '-') { bsdtar_warnc(bsdtar, 0, "List of objects to archive includes '%s'." " This might not be what you intended.", bsdtar->argv[i]); break; } } a = archive_write_new(); /* We only support the pax restricted format. */ archive_write_set_format_pax_restricted(a); /* Set the block size to zero -- we don't want buffering. */ archive_write_set_bytes_per_block(a, 0); /* Open the archive, keeping a cookie for talking to the tape layer. */ bsdtar->write_cookie = archive_write_open_multitape(a, bsdtar->machinenum, bsdtar->cachedir, bsdtar->tapenames[0], bsdtar->argc_orig, bsdtar->argv_orig, bsdtar->option_print_stats, bsdtar->option_dryrun, bsdtar->creationtime); if (bsdtar->write_cookie == NULL) bsdtar_errc(bsdtar, 1, 0, "%s", archive_error_string(a)); /* * Remember the device and inode numbers of the cache directory, so * that we can skip is in write_hierarchy(). */ if (getdevino(a, bsdtar->cachedir, &bsdtar->cachedir_dev, &bsdtar->cachedir_ino)) bsdtar_errc(bsdtar, 1, 0, "%s", archive_error_string(a)); /* If the chunkification cache is enabled, read it. */ if ((bsdtar->cachecrunch < 2) && (bsdtar->cachedir != NULL)) { bsdtar->chunk_cache = ccache_read(bsdtar->cachedir); if (bsdtar->chunk_cache == NULL) bsdtar_errc(bsdtar, 1, errno, "Error reading cache"); } write_archive(a, bsdtar); /* * If this isn't a dry run and we're running with the chunkification * cache enabled, write the cache back to disk. */ if ((bsdtar->option_dryrun == 0) && (bsdtar->cachecrunch < 2)) { if (ccache_write(bsdtar->chunk_cache, bsdtar->cachedir)) bsdtar_errc(bsdtar, 1, errno, "Error writing cache"); } /* Free the chunkification cache. */ if (bsdtar->cachecrunch < 2) ccache_free(bsdtar->chunk_cache); }
static void test_options(const char *options) { struct archive_entry *ae; struct archive* a; char *buff, *data; size_t buffsize, datasize; char path[16]; size_t used1; int i, r, use_prog = 0, filecount; assert((a = archive_write_new()) != NULL); r = archive_write_add_filter_lz4(a); if (archive_liblz4_version() == NULL) { if (!canLz4()) { skipping("lz4 writing not supported on this platform"); assertEqualInt(ARCHIVE_WARN, r); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); return; } else { assertEqualInt(ARCHIVE_WARN, r); use_prog = 1; } } else { assertEqualInt(ARCHIVE_OK, r); } buffsize = 2000000; assert(NULL != (buff = (char *)malloc(buffsize))); datasize = 10000; assert(NULL != (data = (char *)calloc(1, datasize))); filecount = 10; /* * Write a filecount files and read them all back. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, archive_write_add_filter_lz4(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, options)); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1024)); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1024)); assertEqualInt(ARCHIVE_FILTER_LZ4, archive_filter_code(a, 0)); assertEqualString("lz4", archive_filter_name(a, 0)); assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used1)); assert((ae = archive_entry_new()) != NULL); archive_entry_set_filetype(ae, AE_IFREG); archive_entry_set_size(ae, datasize); for (i = 0; i < filecount; i++) { sprintf(path, "file%03d", i); archive_entry_copy_pathname(ae, path); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); assertA(datasize == (size_t)archive_write_data(a, data, datasize)); } archive_entry_free(ae); assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); r = archive_read_support_filter_lz4(a); if (r == ARCHIVE_WARN) { skipping("Can't verify lz4 writing by reading back;" " lz4 reading not fully supported on this platform"); } else { assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used1)); for (i = 0; i < filecount; i++) { sprintf(path, "file%03d", i); if (!assertEqualInt(ARCHIVE_OK, archive_read_next_header(a, &ae))) break; assertEqualString(path, archive_entry_pathname(ae)); assertEqualInt((int)datasize, archive_entry_size(ae)); } assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); } assertEqualInt(ARCHIVE_OK, archive_read_free(a)); /* * Clean up. */ free(data); free(buff); }
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; }
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 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); }
static void test_filter_by_name(const char *filter_name, int filter_code, int (*can_filter_prog)(void)) { struct archive_entry *ae; struct archive *a; size_t used; size_t buffsize = 1024 * 128; char *buff; int r; assert((buff = malloc(buffsize)) != NULL); if (buff == NULL) return; /* Create a new archive in memory. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); r = archive_write_add_filter_by_name(a, filter_name); if (r == ARCHIVE_WARN) { if (!can_filter_prog()) { skipping("%s filter not suported on this platform", filter_name); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); free(buff); return; } } else if (r == ARCHIVE_FATAL && (strcmp(archive_error_string(a), "lzma compression not supported on this platform") == 0 || strcmp(archive_error_string(a), "xz compression not supported on this platform") == 0)) { skipping("%s filter not suported on this platform", filter_name); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); free(buff); return; } else { if (!assertEqualIntA(a, ARCHIVE_OK, r)) { assertEqualInt(ARCHIVE_OK, archive_write_free(a)); free(buff); return; } } assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 10)); assertEqualIntA(a, ARCHIVE_OK, 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, 0); assertEqualInt(1, archive_entry_mtime(ae)); archive_entry_set_ctime(ae, 1, 0); assertEqualInt(1, archive_entry_ctime(ae)); archive_entry_set_atime(ae, 1, 0); assertEqualInt(1, archive_entry_atime(ae)); archive_entry_copy_pathname(ae, "file"); assertEqualString("file", archive_entry_pathname(ae)); archive_entry_set_mode(ae, AE_IFREG | 0755); assertEqualInt((AE_IFREG | 0755), archive_entry_mode(ae)); archive_entry_set_size(ae, 8); assertEqualInt(0, archive_write_header(a, ae)); archive_entry_free(ae); assertEqualInt(8, archive_write_data(a, "12345678", 8)); /* 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_memory(a, buff, used)); /* * Read and verify the file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualInt(1, archive_entry_mtime(ae)); assertEqualString("file", archive_entry_pathname(ae)); assertEqualInt(AE_IFREG, archive_entry_filetype(ae)); assertEqualInt(8, archive_entry_size(ae)); /* Verify the end of the archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, filter_code, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_USTAR, archive_format(a)); assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); free(buff); }
/* * 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_add_filter_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 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); }
/* * 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_add_filter_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)); }
/* ArchiveWriter::__construct {{{ * */ ZEND_METHOD(ArchiveWriter, __construct) { archive_file_t *arch = NULL; int resource_id; zval *this = getThis(); const char *error_string = NULL; char *filename; long error_num, filename_len, result, format=0, compression=0; zend_error_handling error_handling; zend_replace_error_handling(EH_THROW, ce_ArchiveException, &error_handling TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &filename, &filename_len, &format, &compression) == FAILURE) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } #if PHP_API_VERSION < 20100412 if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } #endif if (php_check_open_basedir(filename TSRMLS_CC)) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } arch = (archive_file_t *) emalloc(sizeof(archive_file_t)); arch->stream = NULL; ALLOC_HASHTABLE(arch->entries); zend_hash_init(arch->entries, 10, NULL, _archive_entries_hash_dtor, 0); arch->mode = PHP_ARCHIVE_WRITE_MODE; arch->buf = emalloc(PHP_ARCHIVE_BUF_LEN + 1); arch->filename = estrndup(filename, filename_len); arch->arch = archive_write_new(); switch (compression) { case PHP_ARCHIVE_COMPRESSION_GZIP: if (archive_write_add_filter_gzip(arch->arch) != ARCHIVE_OK) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Gzip compression is not supported in this build"); zend_restore_error_handling(&error_handling TSRMLS_CC); return; } break; case PHP_ARCHIVE_COMPRESSION_BZIP2: if (archive_write_add_filter_bzip2(arch->arch) != ARCHIVE_OK) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bzip2 compression is not supported in this build"); zend_restore_error_handling(&error_handling TSRMLS_CC); return; } break; case 0: /* default value */ case PHP_ARCHIVE_COMPRESSION_NONE: /* always supported */ break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported compression type %ld", compression); zend_restore_error_handling(&error_handling TSRMLS_CC); return; break; } switch (format) { case 0: /* default value */ case PHP_ARCHIVE_FORMAT_TAR: case PHP_ARCHIVE_FORMAT_PAX_RESTRICTED: archive_write_set_format_pax_restricted(arch->arch); break; case PHP_ARCHIVE_FORMAT_PAX: archive_write_set_format_pax(arch->arch); break; case PHP_ARCHIVE_FORMAT_CPIO: archive_write_set_format_cpio(arch->arch); break; case PHP_ARCHIVE_FORMAT_SHAR: archive_write_set_format_shar(arch->arch); break; case PHP_ARCHIVE_FORMAT_USTAR: archive_write_set_format_ustar(arch->arch); break; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported archive format: %ld", format); zend_restore_error_handling(&error_handling TSRMLS_CC); return; break; } archive_write_set_bytes_per_block(arch->arch, DEFAULT_BYTES_PER_BLOCK); result = archive_write_open(arch->arch, arch, _archive_open_clbk, _archive_write_clbk, _archive_close_clbk); /* do not pad the last block */ archive_write_set_bytes_in_last_block(arch->arch, 1); if (result) { error_num = archive_errno(arch->arch); error_string = archive_error_string(arch->arch); efree(arch->filename); efree(arch->buf); efree(arch); if (error_num && error_string) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open file %s for writing: error #%ld, %s", filename, error_num, error_string); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open file %s for writing: unknown error %ld", filename, result); } zend_restore_error_handling(&error_handling TSRMLS_CC); return; } resource_id = zend_list_insert(arch,le_archive); add_property_resource(this, "fd", resource_id); zend_restore_error_handling(&error_handling TSRMLS_CC); return; }
void tar_mode_c(struct bsdtar *bsdtar) { struct archive *a; int r; if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) lafe_errc(1, 0, "no files or directories specified"); a = archive_write_new(); /* Support any format that the library supports. */ if (bsdtar->create_format == NULL) { r = archive_write_set_format_pax_restricted(a); bsdtar->create_format = "pax restricted"; } else { r = archive_write_set_format_by_name(a, bsdtar->create_format); } if (r != ARCHIVE_OK) { fprintf(stderr, "Can't use format %s: %s\n", bsdtar->create_format, archive_error_string(a)); usage(); } archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); archive_write_set_bytes_in_last_block(a, bsdtar->bytes_in_last_block); if (bsdtar->compress_program) { archive_write_set_compression_program(a, bsdtar->compress_program); } else { switch (bsdtar->create_compression) { case 0: r = ARCHIVE_OK; break; case 'j': case 'y': r = archive_write_set_compression_bzip2(a); break; case 'J': r = archive_write_set_compression_xz(a); break; case OPTION_LZIP: r = archive_write_set_compression_lzip(a); break; case OPTION_LZMA: r = archive_write_set_compression_lzma(a); break; case 'z': r = archive_write_set_compression_gzip(a); break; case 'Z': r = archive_write_set_compression_compress(a); break; default: lafe_errc(1, 0, "Unrecognized compression option -%c", bsdtar->create_compression); } if (r != ARCHIVE_OK) { lafe_errc(1, 0, "Unsupported compression option -%c", bsdtar->create_compression); } } if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options)) lafe_errc(1, 0, "%s", archive_error_string(a)); if (ARCHIVE_OK != archive_write_open_file(a, bsdtar->filename)) lafe_errc(1, 0, "%s", archive_error_string(a)); write_archive(a, bsdtar); }
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_add_filter_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 int create_iso_image(unsigned char *buff, size_t buffsize, size_t *used, const char *opt) { struct archive *a; int i, l, fcnt; const int lens[] = { 0, 1, 3, 5, 7, 8, 9, 29, 30, 31, 32, 62, 63, 64, 65, 101, 102, 103, 104, 191, 192, 193, 194, 204, 205, 206, 207, 208, 252, 253, 254, 255, -1 }; char fname1[256]; char fname2[256]; char sym1[2]; char sym128[129]; char sym255[256]; /* ISO9660 format: Create a new archive in memory. */ assert((a = archive_write_new()) != NULL); assertA(0 == archive_write_set_format_iso9660(a)); assertA(0 == archive_write_add_filter_none(a)); assertA(0 == archive_write_set_option(a, NULL, "pad", NULL)); if (opt) assertA(0 == archive_write_set_options(a, opt)); assertA(0 == archive_write_set_bytes_per_block(a, 1)); assertA(0 == archive_write_set_bytes_in_last_block(a, 1)); assertA(0 == archive_write_open_memory(a, buff, buffsize, used)); sym1[0] = 'x'; sym1[1] = '\0'; for (i = 0; i < (int)sizeof(sym128)-2; i++) sym128[i] = 'a'; sym128[sizeof(sym128)-2] = 'x'; sym128[sizeof(sym128)-1] = '\0'; for (i = 0; i < (int)sizeof(sym255)-2; i++) sym255[i] = 'a'; sym255[sizeof(sym255)-2] = 'x'; sym255[sizeof(sym255)-1] = '\0'; fcnt = 0; for (i = 0; lens[i] >= 0; i++) { for (l = 0; l < lens[i]; l++) { fname1[l] = 'a'; fname2[l] = 'A'; } if (l > 0) { fname1[l] = '\0'; fname2[l] = '\0'; add_entry(a, fname1, NULL); add_entry(a, fname2, sym1); fcnt += 2; } if (l < 254) { fname1[l] = '.'; fname1[l+1] = 'c'; fname1[l+2] = '\0'; fname2[l] = '.'; fname2[l+1] = 'C'; fname2[l+2] = '\0'; add_entry(a, fname1, sym128); add_entry(a, fname2, sym255); fcnt += 2; } if (l < 252) { fname1[l] = '.'; fname1[l+1] = 'p'; fname1[l+2] = 'n'; fname1[l+3] = 'g'; fname1[l+4] = '\0'; fname2[l] = '.'; fname2[l+1] = 'P'; fname2[l+2] = 'N'; fname2[l+3] = 'G'; fname2[l+4] = '\0'; add_entry(a, fname1, NULL); add_entry(a, fname2, sym1); fcnt += 2; } if (l < 251) { fname1[l] = '.'; fname1[l+1] = 'j'; fname1[l+2] = 'p'; fname1[l+3] = 'e'; fname1[l+4] = 'g'; fname1[l+5] = '\0'; fname2[l] = '.'; fname2[l+1] = 'J'; fname2[l+2] = 'P'; fname2[l+3] = 'E'; fname2[l+4] = 'G'; fname2[l+5] = '\0'; add_entry(a, fname1, sym128); add_entry(a, fname2, sym255); fcnt += 2; } } /* Close out the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a)); return (fcnt); }