csomh / source-git / rpm

Forked from source-git/rpm 4 years ago
Clone
2ff057
/* rpmarchive: spit out the main archive portion of a package */
2ff057
2ff057
#include "system.h"
2ff057
2ff057
#include <rpm/rpmlib.h>		/* rpmReadPackageFile .. */
2ff057
#include <rpm/rpmfi.h>
2ff057
#include <rpm/rpmtag.h>
2ff057
#include <rpm/rpmio.h>
2ff057
#include <rpm/rpmpgp.h>
2ff057
2ff057
#include <rpm/rpmts.h>
2ff057
2ff057
#include <archive.h>
2ff057
#include <archive_entry.h>
2ff057
#include <unistd.h>
2ff057
2ff057
#include "debug.h"
2ff057
2ff057
#define BUFSIZE (128*1024)
2ff057
2ff057
static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi)
2ff057
{
2ff057
    archive_entry_clear(entry);
2ff057
2ff057
    char * filename = rstrscat(NULL, ".", rpmfiDN(fi), rpmfiBN(fi), NULL);
2ff057
    archive_entry_copy_pathname(entry, filename);
2ff057
    _free(filename);
2ff057
2ff057
    archive_entry_set_size(entry, rpmfiFSize(fi));
2ff057
    rpm_mode_t mode = rpmfiFMode(fi);
2ff057
    archive_entry_set_filetype(entry, mode & S_IFMT);
2ff057
    archive_entry_set_perm(entry, mode);
2ff057
2ff057
    archive_entry_set_uname(entry, rpmfiFUser(fi));
2ff057
    archive_entry_set_gname(entry, rpmfiFGroup(fi));
2ff057
    archive_entry_set_rdev(entry, rpmfiFRdev(fi));
2ff057
    archive_entry_set_mtime(entry, rpmfiFMtime(fi), 0);
2ff057
2ff057
    if (S_ISLNK(mode))
2ff057
	archive_entry_set_symlink(entry, rpmfiFLink(fi));
2ff057
}
2ff057
2ff057
static void write_file_content(struct archive * a, char * buf, rpmfi fi)
2ff057
{
2ff057
    rpm_loff_t left = rpmfiFSize(fi);
2ff057
    size_t len, read;
2ff057
2ff057
    while (left) {
2ff057
	len = (left > BUFSIZE ? BUFSIZE : left);
2ff057
	read = rpmfiArchiveRead(fi, buf, len);
2ff057
	if (read==len) {
2ff057
	    archive_write_data(a, buf, len);
2ff057
	} else {
2ff057
	    fprintf(stderr, "Error reading file from rpm payload\n");
2ff057
	    break;
2ff057
	}
2ff057
	left -= len;
2ff057
    }
2ff057
}
2ff057
2ff057
static int process_package(rpmts ts, char * filename)
2ff057
{
2ff057
    FD_t fdi;
2ff057
    FD_t gzdi;
2ff057
    Header h;
2ff057
    int rc = 0;
2ff057
    char * rpmio_flags = NULL;
2ff057
    struct archive *a;
2ff057
    struct archive_entry *entry;
2ff057
2ff057
    if (!strcmp(filename, "-")) {
2ff057
	fdi = fdDup(STDIN_FILENO);
2ff057
    } else {
2ff057
	fdi = Fopen(filename, "r.ufdio");
2ff057
    }
2ff057
2ff057
    if (Ferror(fdi)) {
2ff057
	fprintf(stderr, "rpm2archive: %s: %s\n",
2ff057
		filename, Fstrerror(fdi));
2ff057
	exit(EXIT_FAILURE);
2ff057
    }
2ff057
2ff057
    rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h);
2ff057
2ff057
    switch (rc) {
2ff057
    case RPMRC_OK:
2ff057
    case RPMRC_NOKEY:
2ff057
    case RPMRC_NOTTRUSTED:
2ff057
	break;
2ff057
    case RPMRC_NOTFOUND:
2ff057
	fprintf(stderr, _("argument is not an RPM package\n"));
2ff057
	exit(EXIT_FAILURE);
2ff057
	break;
2ff057
    case RPMRC_FAIL:
2ff057
    default:
2ff057
	fprintf(stderr, _("error reading header from package\n"));
2ff057
	exit(EXIT_FAILURE);
2ff057
	break;
2ff057
    }
2ff057
2ff057
2ff057
    /* Retrieve payload size and compression type. */
2ff057
    {	const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
2ff057
	rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
2ff057
    }
2ff057
2ff057
    gzdi = Fdopen(fdi, rpmio_flags);	/* XXX gzdi == fdi */
2ff057
    free(rpmio_flags);
2ff057
2ff057
    if (gzdi == NULL) {
2ff057
	fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
2ff057
	exit(EXIT_FAILURE);
2ff057
    }
2ff057
2ff057
    rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
2ff057
    rpmfi fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);
2ff057
2ff057
    /* create archive */
2ff057
    a = archive_write_new();
2ff057
    archive_write_add_filter_gzip(a);
2ff057
    archive_write_set_format_pax_restricted(a);
2ff057
2ff057
    if (!strcmp(filename, "-")) {
2ff057
	if (isatty(STDOUT_FILENO)) {
2ff057
	    fprintf(stderr, "Error: refusing to output archive data to a terminal.\n");
2ff057
	    exit(EXIT_FAILURE);
2ff057
	}
2ff057
	archive_write_open_fd(a, STDOUT_FILENO);
2ff057
    } else {
2ff057
	char * outname = rstrscat(NULL, filename, ".tgz", NULL);
2ff057
	archive_write_open_filename(a, outname);
2ff057
	_free(outname);
2ff057
	// XXX error handling
2ff057
    }
2ff057
2ff057
    entry = archive_entry_new();
2ff057
2ff057
    char * buf = xmalloc(BUFSIZE);
2ff057
    char * hardlink = NULL;
2ff057
2ff057
    rc = 0;
2ff057
    while (rc >= 0) {
2ff057
	rc = rpmfiNext(fi);
2ff057
	if (rc == RPMERR_ITER_END) {
2ff057
	    break;
2ff057
	}
2ff057
2ff057
	rpm_mode_t mode = rpmfiFMode(fi);
2ff057
	int nlink = rpmfiFNlink(fi);
2ff057
2ff057
	fill_archive_entry(a, entry, fi);
2ff057
2ff057
	if (nlink > 1) {
2ff057
	    if (rpmfiArchiveHasContent(fi)) {
2ff057
		_free(hardlink);
2ff057
		hardlink = rstrscat(NULL, ".", rpmfiFN(fi), NULL);
2ff057
	    } else {
2ff057
		archive_entry_set_hardlink(entry, hardlink);
2ff057
	    }
2ff057
	}
2ff057
2ff057
	archive_write_header(a, entry);
2ff057
2ff057
	if (S_ISREG(mode) && (nlink == 1 || rpmfiArchiveHasContent(fi))) {
2ff057
	    write_file_content(a, buf, fi);
2ff057
	}
2ff057
    }
2ff057
    /* End of iteration is not an error */
2ff057
    if (rc == RPMERR_ITER_END) {
2ff057
	rc = 0;
2ff057
    }
2ff057
2ff057
    _free(hardlink);
2ff057
2ff057
    Fclose(gzdi);	/* XXX gzdi == fdi */
2ff057
    archive_entry_free(entry);
2ff057
    archive_write_close(a);
2ff057
    archive_write_free(a);
2ff057
    buf = _free(buf);
2ff057
    rpmfilesFree(files);
2ff057
    rpmfiFree(fi);
2ff057
    headerFree(h);
2ff057
    return rc;
2ff057
}
2ff057
2ff057
int main(int argc, char *argv[])
2ff057
{
2ff057
    int rc;
2ff057
    
2ff057
    xsetprogname(argv[0]);	/* Portability call -- see system.h */
2ff057
    rpmReadConfigFiles(NULL, NULL);
2ff057
    char * filename;
2ff057
    if (argc == 1)
2ff057
	filename = "-";
2ff057
    else {
2ff057
	if (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")) {
2ff057
	    fprintf(stderr, "Usage: rpm2archive file.rpm\n");
2ff057
	    exit(EXIT_FAILURE);
2ff057
	} else {
2ff057
	    filename = argv[1];
2ff057
	}
2ff057
    }
2ff057
2ff057
    rpmts ts = rpmtsCreate();
2ff057
    rpmVSFlags vsflags = 0;
2ff057
2ff057
    /* XXX retain the ageless behavior of rpm2cpio */
2ff057
    vsflags |= RPMVSF_MASK_NODIGESTS;
2ff057
    vsflags |= RPMVSF_MASK_NOSIGNATURES;
2ff057
    vsflags |= RPMVSF_NOHDRCHK;
2ff057
    (void) rpmtsSetVSFlags(ts, vsflags);
2ff057
2ff057
    rc = process_package(ts, filename);
2ff057
2ff057
    ts = rpmtsFree(ts);
2ff057
2ff057
    return rc;
2ff057
}