void PictureBank::loadArchive(const std::string &filename) { std::cout << "reading image archive: " << filename << std::endl; struct archive *a; struct archive_entry *entry; int rc; a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_all(a); rc = archive_read_open_filename(a, filename.c_str(), 16384); // block size if (rc != ARCHIVE_OK) { THROW("Cannot open archive " << filename); } SDL_Surface *surface; SDL_RWops *rw; const Uint32 bufferSize = 10000000; // allocated buffer std::auto_ptr< Uint8 > buffer( new Uint8[ bufferSize ] ); if( buffer.get() == 0 ) THROW("Memory error, cannot allocate buffer size " << bufferSize); std::string entryname; while( archive_read_next_header(a, &entry) == ARCHIVE_OK ) { // for all entries in archive entryname = archive_entry_pathname(entry); if ((archive_entry_stat(entry)->st_mode & S_IFREG) == 0) { // not a regular file (maybe a directory). skip it. continue; } if (archive_entry_stat(entry)->st_size >= bufferSize) { THROW("Cannot load archive: file is too big " << entryname << " in archive " << filename); } int size = archive_read_data(a, buffer.get(), bufferSize); // read data into buffer rw = SDL_RWFromMem(buffer.get(), size); surface = IMG_Load_RW(rw, 0); SDL_SetAlpha( surface, 0, 0 ); setPicture(entryname, *surface); SDL_FreeRW(rw); } rc = archive_read_finish(a); if (rc != ARCHIVE_OK) { THROW("Error while reading archive " << filename); } }
/* Return a pointer to the next file in the archive `a' */ static struct pkg_file * freebsd_get_next_entry(struct archive *a) { uint64_t length; char *str; struct archive_entry *entry; const struct stat *sb; assert(a != NULL); /* Read the next entry to a buffer. */ if (archive_read_next_header(a, &entry) != ARCHIVE_OK) { return NULL; } /* Allocate enough space for the file and copy it to the string */ length = archive_entry_size(entry); str = malloc(length+1); if (!str) { return NULL; } archive_read_data_into_buffer(a, str, length); str[length] = '\0'; /* Get the needed struct stat from the archive */ sb = archive_entry_stat(entry); /* Create the pkg_file and return it */ return pkg_file_new_from_buffer(archive_entry_pathname(entry), length, str, sb); }
size_t pkg_archive_get_size(const char *path){ struct archive *a; struct archive_entry *entry; size_t size = 0; struct stat *f_stat; int r; a = pkg_archive_open(path); if(a == NULL) return -1; for(;;){ r = archive_read_next_header(a, &entry); if(r == ARCHIVE_EOF) break; if(r != ARCHIVE_OK){ pkg_archive_close(a); return -1; } f_stat = (struct stat *)archive_entry_stat(entry); size += f_stat->st_size; } return size; }
/* * Extract all of the archive members of the specified archive * object. If dest is not NULL, extract archive members to that * directory. If dest is not NULL and does not exist as a directory, * create it first. Return ARCHIVE_OK on success, ARCHIVE_* otherwise. */ int unpack_members_and_finish(struct archive *a, char *dest, filterfunc filter, void* userptr) { int restore = 0; char prevcwd[PATH_MAX]; struct archive_entry *e = NULL; if (getcwd(prevcwd, PATH_MAX) == NULL) { logMessage(ERROR, "unable to getcwd() (%s:%d): %m", __func__, __LINE__); return ARCHIVE_FATAL; } else { restore = 1; } if (dest != NULL) { if (unpack_mkpath(dest) != ARCHIVE_OK) { return ARCHIVE_FATAL; } else if (chdir(dest) == -1) { logMessage(ERROR, "unable to chdir %s (%s:%d): %m", dest, __func__, __LINE__); return ARCHIVE_FATAL; } } while (archive_read_next_header(a, &e) == ARCHIVE_OK) { const char *pathname = archive_entry_pathname(e); const struct stat *fstat = archive_entry_stat(e); if (filter && filter(pathname, fstat, userptr)) continue; if (archive_read_extract(a, e, 0) != ARCHIVE_OK) { logMessage(ERROR, "error unpacking %s (%s:%d): %s", pathname, __func__, __LINE__, archive_error_string(a)); return ARCHIVE_FATAL; } } if (restore && chdir(prevcwd) == -1) { logMessage(ERROR, "unable to chdir %s (%s:%d): %m", dest, __func__, __LINE__); return ARCHIVE_FATAL; } if (archive_read_finish(a) != ARCHIVE_OK) { logMessage(ERROR, "error closing archive (%s:%d): %s", __func__, __LINE__, archive_error_string(a)); return ARCHIVE_FATAL; } return ARCHIVE_OK; }
static int append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) { struct archive_entry *in_entry; int e; while (0 == archive_read_next_header(ina, &in_entry)) { if (!new_enough(bsdtar, archive_entry_pathname(in_entry), archive_entry_stat(in_entry))) continue; if (excluded(bsdtar, archive_entry_pathname(in_entry))) continue; if (bsdtar->option_interactive && !yes("copy '%s'", archive_entry_pathname(in_entry))) continue; if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(in_entry)); siginfo_setinfo(bsdtar, "copying", archive_entry_pathname(in_entry), archive_entry_size(in_entry)); siginfo_printinfo(bsdtar, 0); e = archive_write_header(a, in_entry); if (e != ARCHIVE_OK) { if (!bsdtar->verbose) bsdtar_warnc(bsdtar, 0, "%s: %s", archive_entry_pathname(in_entry), archive_error_string(a)); else fprintf(stderr, ": %s", archive_error_string(a)); } if (e == ARCHIVE_FATAL) exit(1); if (e >= ARCHIVE_WARN) { if (archive_entry_size(in_entry) == 0) archive_read_data_skip(ina); else if (copy_file_data(bsdtar, a, ina)) exit(1); } if (bsdtar->verbose) fprintf(stderr, "\n"); } /* Note: If we got here, we saw no write errors, so return success. */ return (0); }
static int append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) { struct archive_entry *in_entry; int e; while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) { if (!new_enough(bsdtar, archive_entry_pathname(in_entry), archive_entry_stat(in_entry))) continue; if (lafe_excluded(bsdtar->matching, archive_entry_pathname(in_entry))) continue; if (bsdtar->option_interactive && !yes("copy '%s'", archive_entry_pathname(in_entry))) continue; if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(in_entry)); if (need_report()) report_write(bsdtar, a, in_entry, 0); e = archive_write_header(a, in_entry); if (e != ARCHIVE_OK) { if (!bsdtar->verbose) lafe_warnc(0, "%s: %s", archive_entry_pathname(in_entry), archive_error_string(a)); else fprintf(stderr, ": %s", archive_error_string(a)); } if (e == ARCHIVE_FATAL) exit(1); if (e >= ARCHIVE_WARN) { if (archive_entry_size(in_entry) == 0) archive_read_data_skip(ina); else if (copy_file_data(bsdtar, a, ina, in_entry)) exit(1); } if (bsdtar->verbose) fprintf(stderr, "\n"); } return (e == ARCHIVE_EOF ? ARCHIVE_OK : e); }
static int do_extract(struct archive *a, struct archive_entry *ae, const char *location, int nfiles, struct pkg *pkg, struct pkg *local) { int retcode = EPKG_OK; int ret = 0, cur_file = 0; char path[MAXPATHLEN], pathname[MAXPATHLEN], rpath[MAXPATHLEN]; struct stat st; const struct stat *aest; bool renamed = false; const struct pkg_file *rf; struct pkg_config_file *rcf; struct sbuf *newconf; bool automerge = pkg_object_bool(pkg_config_get("AUTOMERGE")); unsigned long set, clear; #ifndef HAVE_ARC4RANDOM srand(time(NULL)); #endif if (nfiles == 0) return (EPKG_OK); pkg_emit_extract_begin(pkg); pkg_emit_progress_start(NULL); newconf = sbuf_new_auto(); do { ret = ARCHIVE_OK; sbuf_clear(newconf); rf = NULL; rcf = NULL; pkg_absolutepath(archive_entry_pathname(ae), path, sizeof(path)); snprintf(pathname, sizeof(pathname), "%s%s%s", location ? location : "", *path == '/' ? "" : "/", path ); strlcpy(rpath, pathname, sizeof(rpath)); aest = archive_entry_stat(ae); archive_entry_fflags(ae, &set, &clear); if (lstat(rpath, &st) != -1) { /* * We have an existing file on the path, so handle it */ if (!S_ISDIR(aest->st_mode)) { pkg_debug(2, "Old version found, renaming"); pkg_add_file_random_suffix(rpath, sizeof(rpath), 12); renamed = true; } if (!S_ISDIR(st.st_mode) && S_ISDIR(aest->st_mode)) { if (S_ISLNK(st.st_mode)) { if (stat(rpath, &st) == -1) { pkg_emit_error("Dead symlink %s", rpath); } else { pkg_debug(2, "Directory is a symlink, use it"); pkg_emit_progress_tick(cur_file++, nfiles); continue; } } } } archive_entry_set_pathname(ae, rpath); /* load in memory the content of config files */ if (pkg_is_config_file(pkg, path, &rf, &rcf)) { pkg_debug(1, "Populating config_file %s", pathname); size_t len = archive_entry_size(ae); rcf->content = malloc(len); archive_read_data(a, rcf->content, len); if (renamed && (!automerge || local == NULL)) strlcat(pathname, ".pkgnew", sizeof(pathname)); } /* * check if the file is already provided by previous package */ if (!automerge) attempt_to_merge(renamed, rcf, local, pathname, path, newconf); if (sbuf_len(newconf) == 0 && (rcf == NULL || rcf->content == NULL)) { pkg_debug(1, "Extracting: %s", archive_entry_pathname(ae)); int install_as_user = (getenv("INSTALL_AS_USER") != NULL); int extract_flags = EXTRACT_ARCHIVE_FLAGS; if (install_as_user) { /* when installing as user don't try to set file ownership */ extract_flags &= ~ARCHIVE_EXTRACT_OWNER; } ret = archive_read_extract(a, ae, extract_flags); } else { if (sbuf_len(newconf) == 0) { sbuf_cat(newconf, rcf->content); sbuf_finish(newconf); } pkg_debug(2, "Writing conf in %s", pathname); unlink(rpath); FILE *f = fopen(rpath, "w+"); fprintf(f, "%s", sbuf_data(newconf)); fclose(f); } if (ret != ARCHIVE_OK) { /* * show error except when the failure is during * extracting a directory and that the directory already * exists. * this allow to install packages linux_base from * package for example */ if (archive_entry_filetype(ae) != AE_IFDIR || !is_dir(pathname)) { pkg_emit_error("archive_read_extract(): %s", archive_error_string(a)); retcode = EPKG_FATAL; goto cleanup; } } /* Reapply modes to the directories to work around a problem on FreeBSD 9 */ if (archive_entry_filetype(ae) == AE_IFDIR) chmod(pathname, aest->st_mode); pkg_emit_progress_tick(cur_file++, nfiles); /* Rename old file */ if (renamed) { pkg_debug(1, "Renaming %s -> %s", rpath, pathname); #ifdef HAVE_CHFLAGS bool old = false; if (set & NOCHANGESFLAGS) chflags(rpath, 0); if (lstat(pathname, &st) != -1) { old = true; if (st.st_flags & NOCHANGESFLAGS) chflags(pathname, 0); } #endif if (rename(rpath, pathname) == -1) { #ifdef HAVE_CHFLAGS /* restore flags */ if (old) chflags(pathname, st.st_flags); #endif pkg_emit_error("cannot rename %s to %s: %s", rpath, pathname, strerror(errno)); retcode = EPKG_FATAL; goto cleanup; } #ifdef HAVE_CHFLAGS /* Restore flags */ chflags(pathname, set); #endif } if (string_end_with(pathname, ".pkgnew")) pkg_emit_notice("New configuration file: %s", pathname); renamed = false; } while ((ret = archive_read_next_header(a, &ae)) == ARCHIVE_OK); if (ret != ARCHIVE_EOF) { pkg_emit_error("archive_read_next_header(): %s", archive_error_string(a)); retcode = EPKG_FATAL; } cleanup: pkg_emit_progress_tick(nfiles, nfiles); pkg_emit_extract_finished(pkg); if (renamed && retcode == EPKG_FATAL) { #ifdef HAVE_CHFLAGS if (set & NOCHANGESFLAGS) chflags(rpath, set & ~NOCHANGESFLAGS); #endif unlink(rpath); } return (retcode); }
/* ArchiveWriter::addEntry {{{ * */ ZEND_METHOD(ArchiveWriter, addEntry) { zval *this = getThis(); zval *entry_obj; archive_file_t *arch; archive_entry_t *entry, *entry_copy; char *pathname; int pathname_len; const struct stat *stat_sb; 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, "o", &entry_obj) == FAILURE) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } if (!_archive_get_fd(this, &arch TSRMLS_CC)) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } if (!instanceof_function(Z_OBJCE_P(entry_obj), ce_ArchiveEntry TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "An instance of ArchiveEntry is required"); zend_restore_error_handling(&error_handling TSRMLS_CC); return; } if (!_archive_get_entry_struct(entry_obj, &entry TSRMLS_CC)) { zend_restore_error_handling(&error_handling TSRMLS_CC); return; } pathname = entry->filename; pathname_len = strlen(pathname); _archive_normalize_path(&pathname, &pathname_len); if (pathname_len == 0 || pathname[0] == '\0') { /* user is probably trying to add "./", "/", ".." or ".", ignoring it silently */ zend_restore_error_handling(&error_handling TSRMLS_CC); RETURN_TRUE; } /* copy entry.. */ entry_copy = emalloc(sizeof(archive_entry_t)); memcpy(entry_copy, entry, sizeof(archive_entry_t)); entry_copy->entry = archive_entry_new(); entry_copy->filename = estrdup(entry->filename); entry_copy->data = NULL; entry_copy->data_len = 0; archive_entry_copy_pathname(entry_copy->entry, pathname); stat_sb = archive_entry_stat(entry->entry); archive_entry_copy_stat(entry_copy->entry, stat_sb); /* ..and add it to the hash */ zend_hash_update(arch->entries, pathname, pathname_len + 1, &entry_copy, sizeof(archive_entry_t), NULL); zend_restore_error_handling(&error_handling TSRMLS_CC); RETURN_TRUE; }
/* * Handle 'x' and 't' modes. */ static void read_archive(struct bsdtar *bsdtar, char mode) { FILE *out; struct archive *a; struct archive_entry *entry; const struct stat *st; int r; while (*bsdtar->argv) { include(bsdtar, *bsdtar->argv); bsdtar->argv++; } if (bsdtar->names_from_file != NULL) include_from_file(bsdtar, bsdtar->names_from_file); a = archive_read_new(); if (bsdtar->compress_program != NULL) archive_read_support_compression_program(a, bsdtar->compress_program); else archive_read_support_compression_all(a); archive_read_support_format_all(a); if (archive_read_open_file(a, bsdtar->filename, bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : DEFAULT_BYTES_PER_BLOCK)) bsdtar_errc(bsdtar, 1, 0, "Error opening archive: %s", archive_error_string(a)); do_chdir(bsdtar); for (;;) { /* Support --fast-read option */ if (bsdtar->option_fast_read && unmatched_inclusions(bsdtar) == 0) break; r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (r == ARCHIVE_RETRY) { /* Retryable error: try again */ bsdtar_warnc(bsdtar, 0, "Retrying..."); continue; } if (r == ARCHIVE_FATAL) break; /* * Exclude entries that are too old. */ st = archive_entry_stat(entry); if (bsdtar->newer_ctime_sec > 0) { if (st->st_ctime < bsdtar->newer_ctime_sec) continue; /* Too old, skip it. */ if (st->st_ctime == bsdtar->newer_ctime_sec && ARCHIVE_STAT_CTIME_NANOS(st) <= bsdtar->newer_ctime_nsec) continue; /* Too old, skip it. */ } if (bsdtar->newer_mtime_sec > 0) { if (st->st_mtime < bsdtar->newer_mtime_sec) continue; /* Too old, skip it. */ if (st->st_mtime == bsdtar->newer_mtime_sec && ARCHIVE_STAT_MTIME_NANOS(st) <= bsdtar->newer_mtime_nsec) continue; /* Too old, skip it. */ } /* * Note that pattern exclusions are checked before * pathname rewrites are handled. This gives more * control over exclusions, since rewrites always lose * information. (For example, consider a rewrite * s/foo[0-9]/foo/. If we check exclusions after the * rewrite, there would be no way to exclude foo1/bar * while allowing foo2/bar.) */ if (excluded(bsdtar, archive_entry_pathname(entry))) continue; /* Excluded by a pattern test. */ /* * Modify the pathname as requested by the user. We * do this for -t as well to give users a way to * preview the effects of their rewrites. We also do * this before extraction security checks (including * leading '/' removal). Note that some rewrite * failures prevent extraction. */ if (edit_pathname(bsdtar, entry)) continue; /* Excluded by a rewrite failure. */ if (mode == 't') { /* Perversely, gtar uses -O to mean "send to stderr" * when used with -t. */ out = bsdtar->option_stdout ? stderr : stdout; if (bsdtar->verbose < 2) safe_fprintf(out, "%s", archive_entry_pathname(entry)); else list_item_verbose(bsdtar, out, entry); fflush(out); r = archive_read_data_skip(a); if (r == ARCHIVE_WARN) { fprintf(out, "\n"); bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); } if (r == ARCHIVE_RETRY) { fprintf(out, "\n"); bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); } if (r == ARCHIVE_FATAL) { fprintf(out, "\n"); bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); bsdtar->return_value = 1; break; } fprintf(out, "\n"); } else { if (bsdtar->option_interactive && !yes("extract '%s'", archive_entry_pathname(entry))) continue; /* * Format here is from SUSv2, including the * deferred '\n'. */ if (bsdtar->verbose) { safe_fprintf(stderr, "x %s", archive_entry_pathname(entry)); fflush(stderr); } if (bsdtar->option_stdout) r = archive_read_data_into_fd(a, 1); else r = archive_read_extract(a, entry, bsdtar->extract_flags); if (r != ARCHIVE_OK) { if (!bsdtar->verbose) safe_fprintf(stderr, "%s", archive_entry_pathname(entry)); safe_fprintf(stderr, ": %s", archive_error_string(a)); if (!bsdtar->verbose) fprintf(stderr, "\n"); bsdtar->return_value = 1; } if (bsdtar->verbose) fprintf(stderr, "\n"); if (r == ARCHIVE_FATAL) break; } } if (bsdtar->verbose > 2) fprintf(stdout, "Archive Format: %s, Compression: %s\n", archive_format_name(a), archive_compression_name(a)); archive_read_finish(a); }
/* * Display information about the current file. * * The format here roughly duplicates the output of 'ls -l'. * This is based on SUSv2, where 'tar tv' is documented as * listing additional information in an "unspecified format," * and 'pax -l' is documented as using the same format as 'ls -l'. */ static void list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) { const struct stat *st; char tmp[100]; size_t w; const char *p; const char *fmt; time_t tim; static time_t now; st = archive_entry_stat(entry); /* * We avoid collecting the entire list in memory at once by * listing things as we see them. However, that also means we can't * just pre-compute the field widths. Instead, we start with guesses * and just widen them as necessary. These numbers are completely * arbitrary. */ if (!bsdtar->u_width) { bsdtar->u_width = 6; bsdtar->gs_width = 13; } if (!now) time(&now); fprintf(out, "%s %d ", archive_entry_strmode(entry), (int)(st->st_nlink)); /* Use uname if it's present, else uid. */ p = archive_entry_uname(entry); if ((p == NULL) || (*p == '\0')) { sprintf(tmp, "%lu ", (unsigned long)st->st_uid); p = tmp; } w = strlen(p); if (w > bsdtar->u_width) bsdtar->u_width = w; fprintf(out, "%-*s ", (int)bsdtar->u_width, p); /* Use gname if it's present, else gid. */ p = archive_entry_gname(entry); if (p != NULL && p[0] != '\0') { fprintf(out, "%s", p); w = strlen(p); } else { sprintf(tmp, "%lu", (unsigned long)st->st_gid); w = strlen(tmp); fprintf(out, "%s", tmp); } /* * Print device number or file size, right-aligned so as to make * total width of group and devnum/filesize fields be gs_width. * If gs_width is too small, grow it. */ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { sprintf(tmp, "%lu,%lu", (unsigned long)major(st->st_rdev), (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */ } else { /* * Note the use of platform-dependent macros to format * the filesize here. We need the format string and the * corresponding type for the cast. */ sprintf(tmp, BSDTAR_FILESIZE_PRINTF, (BSDTAR_FILESIZE_TYPE)st->st_size); } if (w + strlen(tmp) >= bsdtar->gs_width) bsdtar->gs_width = w+strlen(tmp)+1; fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp); /* Format the time using 'ls -l' conventions. */ tim = (time_t)st->st_mtime; if (abs(tim - now) > (365/2)*86400) fmt = bsdtar->day_first ? "%e %b %Y" : "%b %e %Y"; else fmt = bsdtar->day_first ? "%e %b %R" : "%b %e %R"; strftime(tmp, sizeof(tmp), fmt, localtime(&tim)); fprintf(out, " %s ", tmp); safe_fprintf(out, "%s", archive_entry_pathname(entry)); /* Extra information for links. */ if (archive_entry_hardlink(entry)) /* Hard link */ safe_fprintf(out, " link to %s", archive_entry_hardlink(entry)); else if (S_ISLNK(st->st_mode)) /* Symbolic link */ safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); }
/* * Handle 'x' and 't' modes. */ static void read_archive(struct bsdtar *bsdtar, char mode) { struct progress_data progress_data; FILE *out; struct archive *a; struct archive_entry *entry; const struct stat *st; int r; while (*bsdtar->argv) { lafe_include(&bsdtar->matching, *bsdtar->argv); bsdtar->argv++; } if (bsdtar->names_from_file != NULL) lafe_include_from_file(&bsdtar->matching, bsdtar->names_from_file, bsdtar->option_null); a = archive_read_new(); if (bsdtar->compress_program != NULL) archive_read_support_compression_program(a, bsdtar->compress_program); else archive_read_support_compression_all(a); archive_read_support_format_all(a); if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options)) lafe_errc(1, 0, "%s", archive_error_string(a)); if (archive_read_open_file(a, bsdtar->filename, bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : DEFAULT_BYTES_PER_BLOCK)) lafe_errc(1, 0, "Error opening archive: %s", archive_error_string(a)); do_chdir(bsdtar); if (mode == 'x') { /* Set an extract callback so that we can handle SIGINFO. */ progress_data.bsdtar = bsdtar; progress_data.archive = a; archive_read_extract_set_progress_callback(a, progress_func, &progress_data); } if (mode == 'x' && bsdtar->option_chroot) { #if HAVE_CHROOT if (chroot(".") != 0) lafe_errc(1, errno, "Can't chroot to \".\""); #else lafe_errc(1, 0, "chroot isn't supported on this platform"); #endif } for (;;) { /* Support --fast-read option */ if (bsdtar->option_fast_read && lafe_unmatched_inclusions(bsdtar->matching) == 0) break; r = archive_read_next_header(a, &entry); progress_data.entry = entry; if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (r == ARCHIVE_RETRY) { /* Retryable error: try again */ lafe_warnc(0, "Retrying..."); continue; } if (r == ARCHIVE_FATAL) break; if (bsdtar->uid >= 0) { archive_entry_set_uid(entry, bsdtar->uid); archive_entry_set_uname(entry, NULL); } if (bsdtar->gid >= 0) { archive_entry_set_gid(entry, bsdtar->gid); archive_entry_set_gname(entry, NULL); } if (bsdtar->uname) archive_entry_set_uname(entry, bsdtar->uname); if (bsdtar->gname) archive_entry_set_gname(entry, bsdtar->gname); /* * Exclude entries that are too old. */ st = archive_entry_stat(entry); if (bsdtar->newer_ctime_sec > 0) { if (st->st_ctime < bsdtar->newer_ctime_sec) continue; /* Too old, skip it. */ if (st->st_ctime == bsdtar->newer_ctime_sec && ARCHIVE_STAT_CTIME_NANOS(st) <= bsdtar->newer_ctime_nsec) continue; /* Too old, skip it. */ } if (bsdtar->newer_mtime_sec > 0) { if (st->st_mtime < bsdtar->newer_mtime_sec) continue; /* Too old, skip it. */ if (st->st_mtime == bsdtar->newer_mtime_sec && ARCHIVE_STAT_MTIME_NANOS(st) <= bsdtar->newer_mtime_nsec) continue; /* Too old, skip it. */ } /* * Note that pattern exclusions are checked before * pathname rewrites are handled. This gives more * control over exclusions, since rewrites always lose * information. (For example, consider a rewrite * s/foo[0-9]/foo/. If we check exclusions after the * rewrite, there would be no way to exclude foo1/bar * while allowing foo2/bar.) */ if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry))) continue; /* Excluded by a pattern test. */ if (mode == 't') { /* Perversely, gtar uses -O to mean "send to stderr" * when used with -t. */ out = bsdtar->option_stdout ? stderr : stdout; /* * TODO: Provide some reasonable way to * preview rewrites. gtar always displays * the unedited path in -t output, which means * you cannot easily preview rewrites. */ if (bsdtar->verbose < 2) safe_fprintf(out, "%s", archive_entry_pathname(entry)); else list_item_verbose(bsdtar, out, entry); fflush(out); r = archive_read_data_skip(a); if (r == ARCHIVE_WARN) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_RETRY) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_FATAL) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); bsdtar->return_value = 1; break; } fprintf(out, "\n"); } else { /* Note: some rewrite failures prevent extraction. */ if (edit_pathname(bsdtar, entry)) continue; /* Excluded by a rewrite failure. */ if (bsdtar->option_interactive && !yes("extract '%s'", archive_entry_pathname(entry))) continue; /* * Format here is from SUSv2, including the * deferred '\n'. */ if (bsdtar->verbose) { safe_fprintf(stderr, "x %s", archive_entry_pathname(entry)); fflush(stderr); } // TODO siginfo_printinfo(bsdtar, 0); if (bsdtar->option_stdout) r = archive_read_data_into_fd(a, 1); else r = archive_read_extract(a, entry, bsdtar->extract_flags); if (r != ARCHIVE_OK) { if (!bsdtar->verbose) safe_fprintf(stderr, "%s", archive_entry_pathname(entry)); safe_fprintf(stderr, ": %s", archive_error_string(a)); if (!bsdtar->verbose) fprintf(stderr, "\n"); bsdtar->return_value = 1; } if (bsdtar->verbose) fprintf(stderr, "\n"); if (r == ARCHIVE_FATAL) break; } } r = archive_read_close(a); if (r != ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (bsdtar->verbose > 2) fprintf(stdout, "Archive Format: %s, Compression: %s\n", archive_format_name(a), archive_compression_name(a)); archive_read_finish(a); }
int cake_insert(cake_config_t *config, cake_package_t *package, char *filename, int flags) { struct archive *archive; struct archive_entry *entry; struct stat st, vst; char *pathname; char *orig_cwd = get_current_dir_name(); pkginfo_t *pkg = NULL; // Open archive archive = archive_read_new(); archive_read_support_compression_all(archive); archive_read_support_format_tar(archive); archive_read_open_filename(archive, filename, 64); chdir(config->install_root); // Check for existing files while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) { pathname = archive_entry_pathname(entry); vst = *archive_entry_stat(entry); // Parse PKGINFO if (!strcmp(pathname, ".PKGINFO")) { int size = archive_entry_size(entry); char buffer[size]; archive_read_data(archive, buffer, size); pkg = pkginfo_read_buffer(buffer); } else { archive_read_data_skip(archive); } } archive_read_finish(archive); // Check if we found pkginfo char *pkgname = pkginfo_get(pkg, "pkgname"); if (pkg == NULL || pkgname == NULL) { fputs("Invalid package, PKGINFO not found or invalid.\n", stderr); return -1; } // Get package specifier cake_package_t *pkgdesc; if (package != NULL) { pkgdesc = package; if (pkgdesc->name == NULL) pkgdesc->name = pkgname; if (pkgdesc->branch == NULL) pkgdesc->branch = "__LOCAL__"; } else { pkgdesc = malloc(sizeof(cake_package_t)); pkgdesc->name = pkgname; pkgdesc->branch = "__LOCAL__"; pkgdesc->server = cake_config_get_server(config, "__LOCAL__"); } // Remove existing package if (cakedb_has(config, pkgdesc)) cake_remove(config, pkgdesc, 0); // Reopen archive chdir(orig_cwd); archive = archive_read_new(); archive_read_support_compression_all(archive); archive_read_support_format_tar(archive); archive_read_open_filename(archive, filename, 64); chdir(config->install_root); // Check for existing files while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) { pathname = archive_entry_pathname(entry); vst = *archive_entry_stat(entry); // Check file existence if (!(flags & CAKE_INSERT_FORCE) && !(vst.st_mode & S_IFDIR) && stat(pathname, &st) == 0) { fprintf(stderr, "Error: file %s%s exists on disk.\n", config->install_root, pathname); return -1; } } archive_read_finish(archive); // Holds all the installed filenames FILE *files = cakedb_open(config, pkgdesc, "files", "w"); // Check if file could be opened if (files == NULL) { fputs("Unable to create database entry, permission denied?\n", stderr); return -1; } // Source origin for the package FILE *sourceloc = cakedb_open(config, pkgdesc, "origin", "w"); fprintf(sourceloc, "%s\n%s\n%s\n", pkgdesc->name, pkgdesc->branch, pkgdesc->server == NULL ? "__LOCAL__" : pkgdesc->server->name); fclose(sourceloc); // Reopen archive chdir(orig_cwd); archive = archive_read_new(); archive_read_support_compression_all(archive); archive_read_support_format_tar(archive); archive_read_open_filename(archive, filename, 64); chdir(config->install_root); // Extract files while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) { pathname = strdup(archive_entry_pathname(entry)); vst = *archive_entry_stat(entry); // Write PKGINFO if (!strcmp(pathname, ".PKGINFO")) { FILE *pkginfo = cakedb_open(config, pkgdesc, "pkginfo", "w"); archive_read_data_into_fd(archive, fileno(pkginfo)); continue; } // Ignore root dotfiles if (pathname[0] == '.') { archive_read_data_skip(archive); continue; } // Move /etc to /usr/etc if (!strncmp(pathname, "etc/", 4)) { if (flags & CAKE_INSERT_INSTALL_CONFIGS) { // Verbose output if (flags & CAKE_INSERT_VERBOSE && pathname[strlen(pathname)-1] != '/') printf("Installing configuration %s\n", pathname); } else { char *newpath = pathname; newpath = malloc(strlen(pathname)+5); sprintf(newpath, "usr/%s", pathname); archive_entry_set_pathname(entry, newpath); } } else { // Verbose output if (flags & CAKE_INSERT_VERBOSE_VERBOSE) printf("Extracting %s\n", pathname); } archive_read_extract(archive, entry, ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_UNLINK); fputs(pathname, files); fputc('\n', files); } // Close archive fclose(files); archive_read_finish(archive); return 0; }
/* * explode source RPM into the current directory * use filters to skip packages and files we do not need */ int explodeRPM(const char *source, filterfunc filter, dependencyfunc provides, dependencyfunc deps, void* userptr) { char buffer[BUFFERSIZE+1]; /* make space for trailing \0 */ FD_t fdi; Header h; char * rpmio_flags = NULL; rpmRC rc; FD_t gzdi; struct archive *cpio; struct archive_entry *cpio_entry; struct cpio_mydata cpio_mydata; rpmts ts; rpmVSFlags vsflags; const char *compr; if (strcmp(source, "-") == 0) fdi = fdDup(STDIN_FILENO); else fdi = Fopen(source, "r.ufdio"); if (Ferror(fdi)) { const char *srcname = (strcmp(source, "-") == 0) ? "<stdin>" : source; logMessage(ERROR, "%s: %s\n", srcname, Fstrerror(fdi)); return EXIT_FAILURE; } rpmReadConfigFiles(NULL, NULL); /* Initialize RPM transaction */ ts = rpmtsCreate(); vsflags = 0; /* Do not check digests, signatures or headers */ vsflags |= _RPMVSF_NODIGESTS; vsflags |= _RPMVSF_NOSIGNATURES; vsflags |= RPMVSF_NOHDRCHK; (void) rpmtsSetVSFlags(ts, vsflags); rc = rpmReadPackageFile(ts, fdi, "rpm2dir", &h); ts = rpmtsFree(ts); switch (rc) { case RPMRC_OK: case RPMRC_NOKEY: case RPMRC_NOTTRUSTED: break; case RPMRC_NOTFOUND: logMessage(ERROR, "%s is not an RPM package", source); return EXIT_FAILURE; break; case RPMRC_FAIL: default: logMessage(ERROR, "error reading header from %s package\n", source); return EXIT_FAILURE; break; } /* Retrieve all dependencies and run them through deps function */ while (deps) { struct rpmtd_s td; const char *depname; if (!headerGet(h, RPMTAG_REQUIRENAME, &td, HEADERGET_MINMEM)) break; /* iterator */ while ((depname = rpmtdNextString(&td))) { if (deps(depname, userptr)) { Fclose(fdi); return EXIT_BADDEPS; } } rpmtdFreeData(&td); break; } /* Retrieve all provides and run them through provides function */ while (provides) { struct rpmtd_s td; const char *depname; int found = 0; if (!headerGet(h, RPMTAG_PROVIDES, &td, HEADERGET_MINMEM)) break; /* iterator */ while ((depname = rpmtdNextString(&td))) { if (!provides(depname, userptr)) { found++; } } rpmtdFreeData(&td); if (found<=0) return EXIT_BADDEPS; break; } /* Retrieve type of payload compression. */ compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); if (compr && strcmp(compr, "gzip")) { checked_asprintf(&rpmio_flags, "r.%sdio", compr); } else { checked_asprintf(&rpmio_flags, "r.gzdio"); } /* Open uncompressed cpio stream */ gzdi = Fdopen(fdi, rpmio_flags); free(rpmio_flags); if (gzdi == NULL) { logMessage(ERROR, "cannot re-open payload: %s\n", Fstrerror(gzdi)); return EXIT_FAILURE; } /* initialize cpio decompressor */ cpio = archive_read_new(); if (cpio==NULL) { Fclose(gzdi); return -1; } cpio_mydata.gzdi = gzdi; cpio_mydata.buffer = buffer; archive_read_support_compression_all(cpio); archive_read_support_format_all(cpio); rc = archive_read_open(cpio, &cpio_mydata, NULL, rpm_myread, rpm_myclose); /* check the status of archive_open */ if (rc != ARCHIVE_OK){ Fclose(gzdi); return -1; } /* read all files in cpio archive */ while ((rc = archive_read_next_header(cpio, &cpio_entry)) == ARCHIVE_OK){ const struct stat *fstat; int64_t fsize; const char* filename; int needskip = 1; /* do we need to read the data to get to the next header? */ int offset = 0; int towrite = 0; filename = archive_entry_pathname(cpio_entry); fstat = archive_entry_stat(cpio_entry); fsize = archive_entry_size(cpio_entry); /* Strip leading slashes */ while (filename[offset] == '/') offset+=1; /* Strip leading ./ */ while (filename[offset] == '.' && filename[offset+1] == '/') offset+=2; /* Other file type - we do not care except special cases */ if (!S_ISREG(fstat->st_mode)) towrite = 1; else towrite = 2; if (filter && filter(filename+offset, fstat, userptr)) { /* filter this file */ towrite = 0; } /* Create directories */ char* dirname = strdup(filename+offset); /* If the dup fails, let's hope the dirs already exist */ if (dirname){ char* dirptr = dirname; while (dirptr && *dirptr) { dirptr = strchr(dirptr, '/'); if (dirptr) { *dirptr = 0; mkdir(dirname, 0700); *dirptr = '/'; dirptr++; } } free(dirname); } /* Regular file */ if (towrite>=2) { FILE *fdout = fopen(filename+offset, "w"); if (fdout==NULL){ rc = 33; break; } rc = archive_read_data_into_fd(cpio, fileno(fdout)); if (rc!=ARCHIVE_OK) { /* XXX We didn't get the file.. well.. */ needskip = 0; } else { needskip = 0; fclose(fdout); } } /* symlink, we assume that the path contained in symlink * is shorter than BUFFERSIZE */ while (towrite && S_ISLNK(fstat->st_mode)) { char symlinkbuffer[BUFFERSIZE-1]; needskip = 0; if ((rc = archive_read_data(cpio, symlinkbuffer, fsize))!=ARCHIVE_OK) { /* XXX We didn't get the file.. well.. */ break; } if (symlink(buffer, filename+offset)) { logMessage(ERROR, "Failed to create symlink %s -> %s", filename+offset, buffer); } break; } if(needskip) archive_read_data_skip(cpio); } archive_read_finish(cpio); return rc != ARCHIVE_OK; }
static int append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina, void * cookie) { struct archive_entry *in_entry; int e; while (0 == archive_read_next_header(ina, &in_entry)) { if (truncate_archive(bsdtar)) break; if (checkpoint_archive(bsdtar, 0)) exit(1); if (cookie == NULL) disk_pause(bsdtar); if (network_select(0)) exit(1); if (!new_enough(bsdtar, archive_entry_pathname(in_entry), archive_entry_stat(in_entry))) continue; if (excluded(bsdtar, archive_entry_pathname(in_entry))) continue; if (bsdtar->option_interactive && !yes("copy '%s'", archive_entry_pathname(in_entry))) continue; if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(in_entry)); siginfo_setinfo(bsdtar, "copying", archive_entry_pathname(in_entry), archive_entry_size(in_entry)); siginfo_printinfo(bsdtar, 0); if (MODE_HEADER(bsdtar, a)) goto err_fatal; e = archive_write_header(a, in_entry); if (e != ARCHIVE_OK) { if (!bsdtar->verbose) bsdtar_warnc(bsdtar, 0, "%s: %s", archive_entry_pathname(in_entry), archive_error_string(a)); else fprintf(stderr, ": %s", archive_error_string(a)); } if (e == ARCHIVE_FATAL) exit(1); if (e < ARCHIVE_WARN) goto done; if (MODE_DATA(bsdtar, a)) goto err_fatal; if (archive_entry_size(in_entry) == 0) archive_read_data_skip(ina); else if (cookie == NULL) { if (copy_file_data(bsdtar, a, ina)) exit(1); } else { switch (archive_multitape_copy(ina, cookie, a, bsdtar->write_cookie)) { case -1: goto err_fatal; case -2: goto err_read; } } done: if (MODE_DONE(bsdtar, a)) goto err_fatal; if (bsdtar->verbose) fprintf(stderr, "\n"); continue; err_read: bsdtar->return_value = 1; if (MODE_DONE(bsdtar, a)) goto err_fatal; if (bsdtar->verbose) fprintf(stderr, "\n"); break; err_fatal: bsdtar_warnc(bsdtar, archive_errno(a), "%s", archive_error_string(a)); exit(1); } /* Note: If we got here, we saw no write errors, so return success. */ return (0); }
/* * Display information about the current file. * * The format here roughly duplicates the output of 'ls -l'. * This is based on SUSv2, where 'tar tv' is documented as * listing additional information in an "unspecified format," * and 'pax -l' is documented as using the same format as 'ls -l'. */ static void list_item_verbose(struct cpio *cpio, struct archive_entry *entry) { char size[32]; char date[32]; char uids[16], gids[16]; const char *uname, *gname; FILE *out = stdout; const struct stat *st; const char *fmt; time_t tim; static time_t now; st = archive_entry_stat(entry); if (!now) time(&now); if (cpio->option_numeric_uid_gid) { /* Format numeric uid/gid for display. */ snprintf(uids, sizeof(uids), "%d", (int)archive_entry_uid(entry)); uname = uids; snprintf(gids, sizeof(gids), "%d", (int)archive_entry_gid(entry)); gname = gids; } else { /* Use uname if it's present, else lookup name from uid. */ uname = archive_entry_uname(entry); if (uname == NULL) uname = lookup_uname(cpio, archive_entry_uid(entry)); /* Use gname if it's present, else lookup name from gid. */ gname = archive_entry_gname(entry); if (gname == NULL) gname = lookup_gname(cpio, archive_entry_gid(entry)); } /* Print device number or file size. */ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { snprintf(size, sizeof(size), "%lu,%lu", (unsigned long)major(st->st_rdev), (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */ } else { snprintf(size, sizeof(size), CPIO_FILESIZE_PRINTF, (CPIO_FILESIZE_TYPE)st->st_size); } /* Format the time using 'ls -l' conventions. */ tim = (time_t)st->st_mtime; #if defined(_WIN32) && !defined(__CYGWIN__) /* Windows' strftime function does not support %e format. */ if (abs(tim - now) > (365/2)*86400) fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y"; else fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M"; #else if (abs(tim - now) > (365/2)*86400) fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y"; else fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M"; #endif strftime(date, sizeof(date), fmt, localtime(&tim)); fprintf(out, "%s%3d %-8s %-8s %8s %12s %s", archive_entry_strmode(entry), archive_entry_nlink(entry), uname, gname, size, date, archive_entry_pathname(entry)); /* Extra information for links. */ if (archive_entry_hardlink(entry)) /* Hard link */ fprintf(out, " link to %s", archive_entry_hardlink(entry)); else if (archive_entry_symlink(entry)) /* Symbolic link */ fprintf(out, " -> %s", archive_entry_symlink(entry)); fprintf(out, "\n"); }