rpm2archive.c
Go to the documentation of this file.
/* rpmarchive: spit out the main archive portion of a package */
#include "system.h"
const char *__progname;
#include <rpm/rpmlib.h> /* rpmReadPackageFile .. */
#include <rpm/rpmfi.h>
#include <rpm/rpmtag.h>
#include <rpm/rpmio.h>
#include <rpm/rpmpgp.h>
#include <rpm/rpmts.h>
#include <archive.h>
#include <archive_entry.h>
#include "debug.h"
#define BUFSIZE (128*1024)
static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi)
{
archive_entry_clear(entry);
char * filename = rstrscat(NULL, ".", rpmfiDN(fi), rpmfiBN(fi), NULL);
archive_entry_copy_pathname(entry, filename);
_free(filename);
archive_entry_set_size(entry, rpmfiFSize(fi));
rpm_mode_t mode = rpmfiFMode(fi);
archive_entry_set_filetype(entry, mode & S_IFMT);
archive_entry_set_perm(entry, mode);
archive_entry_set_uname(entry, rpmfiFUser(fi));
archive_entry_set_gname(entry, rpmfiFGroup(fi));
archive_entry_set_rdev(entry, rpmfiFRdev(fi));
archive_entry_set_mtime(entry, rpmfiFMtime(fi), 0);
if (S_ISLNK(mode))
archive_entry_set_symlink(entry, rpmfiFLink(fi));
}
static void write_file_content(struct archive * a, char * buf, rpmfi fi)
{
rpm_loff_t left = rpmfiFSize(fi);
size_t len, read;
while (left) {
len = (left > BUFSIZE ? BUFSIZE : left);
read = rpmfiArchiveRead(fi, buf, len);
if (read==len) {
archive_write_data(a, buf, len);
} else {
fprintf(stderr, "Error reading file from rpm payload\n");
break;
}
left -= len;
}
}
static int process_package(rpmts ts, char * filename)
{
FD_t fdi;
FD_t gzdi;
Header h;
int rc = 0;
char * rpmio_flags = NULL;
struct archive *a;
struct archive_entry *entry;
if (!strcmp(filename, "-")) {
fdi = fdDup(STDIN_FILENO);
} else {
fdi = Fopen(filename, "r.ufdio");
}
if (Ferror(fdi)) {
fprintf(stderr, "rpm2archive: %s: %s\n",
filename, Fstrerror(fdi));
exit(EXIT_FAILURE);
}
rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h);
switch (rc) {
case RPMRC_OK:
case RPMRC_NOKEY:
case RPMRC_NOTTRUSTED:
break;
case RPMRC_NOTFOUND:
fprintf(stderr, _("argument is not an RPM package\n"));
exit(EXIT_FAILURE);
break;
case RPMRC_FAIL:
default:
fprintf(stderr, _("error reading header from package\n"));
exit(EXIT_FAILURE);
break;
}
/* Retrieve payload size and compression type. */
{ const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
}
gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */
free(rpmio_flags);
if (gzdi == NULL) {
fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
exit(EXIT_FAILURE);
}
rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
rpmfi fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);
/* create archive */
a = archive_write_new();
archive_write_add_filter_gzip(a);
archive_write_set_format_pax_restricted(a);
if (!strcmp(filename, "-")) {
archive_write_open_fd(a, 1);
} else {
char * outname = rstrscat(NULL, filename, ".tgz", NULL);
archive_write_open_filename(a, outname);
_free(outname);
// XXX error handling
}
entry = archive_entry_new();
char * buf = xmalloc(BUFSIZE);
char * hardlink = NULL;
rc = 0;
while (rc >= 0) {
rc = rpmfiNext(fi);
if (rc == RPMERR_ITER_END) {
break;
}
rpm_mode_t mode = rpmfiFMode(fi);
int nlink = rpmfiFNlink(fi);
fill_archive_entry(a, entry, fi);
if (nlink > 1) {
if (rpmfiArchiveHasContent(fi)) {
_free(hardlink);
hardlink = rstrscat(NULL, ".", rpmfiFN(fi), NULL);
} else {
archive_entry_set_hardlink(entry, hardlink);
}
}
archive_write_header(a, entry);
if (S_ISREG(mode) && (nlink == 1 || rpmfiArchiveHasContent(fi))) {
write_file_content(a, buf, fi);
}
}
_free(hardlink);
Fclose(gzdi); /* XXX gzdi == fdi */
archive_entry_free(entry);
archive_write_close(a);
archive_write_free(a);
buf = _free(buf);
rpmfilesFree(files);
rpmfiFree(fi);
headerFree(h);
return rc;
}
int main(int argc, char *argv[])
{
int rc;
setprogname(argv[0]); /* Retrofit glibc __progname */
rpmReadConfigFiles(NULL, NULL);
char * filename;
if (argc == 1)
filename = "-";
else {
if (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")) {
fprintf(stderr, "Usage: rpm2archive file.rpm\n");
exit(EXIT_FAILURE);
} else {
filename = argv[1];
}
}
rpmts ts = rpmtsCreate();
rpmVSFlags vsflags = 0;
/* XXX retain the ageless behavior of rpm2cpio */
vsflags |= _RPMVSF_NODIGESTS;
vsflags |= _RPMVSF_NOSIGNATURES;
vsflags |= RPMVSF_NOHDRCHK;
(void) rpmtsSetVSFlags(ts, vsflags);
rc = process_package(ts, filename);
ts = rpmtsFree(ts);
return rc;
}
setprogname
#define setprogname(pn)
Definition: system.h:99
xmalloc
#define xmalloc(_size)
Definition: system.h:85
rpmfiArchiveRead
size_t rpmfiArchiveRead(rpmfi fi, void *buf, size_t size)
Read content from current file in archive.
FD_t
struct _FD_s * FD_t
RPM IO file descriptor type.
Definition: rpmtypes.h:98
rpmfilesFree
rpmfiles rpmfilesFree(rpmfiles fi)
Destroy a file info set.
debug.h
rstrscat
char * rstrscat(char **dest, const char *arg,...) RPM_GNUC_NULL_TERMINATED
Concatenate multiple strings with dynamically (re)allocated memory.
Fstrerror
const char * Fstrerror(FD_t fd)
strerror(3) clone.
BUFSIZE
#define BUFSIZE
Definition: rpm2archive.c:19
rpmReadPackageFile
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char *fn, Header *hdrp)
Return package header from file handle, verifying digests/signatures.
rpmfiFree
rpmfi rpmfiFree(rpmfi fi)
Destroy a file info set iterator.
RPMFI_KEEPHEADER
Definition: rpmfiles.h:101
RPMRC_NOKEY
Definition: rpmtypes.h:108
_
#define _(Text)
Definition: system.h:112
Fdopen
FD_t Fdopen(FD_t ofd, const char *fmode)
RPMRC_FAIL
Definition: rpmtypes.h:106
rpmfi
struct rpmfi_s * rpmfi
Definition: rpmtypes.h:66
rpmReadConfigFiles
int rpmReadConfigFiles(const char *file, const char *target)
Read macro configuration file(s) for a target.
rpmfilesNew
rpmfiles rpmfilesNew(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
Create and load a file info set.
rpmfiFMtime
rpm_time_t rpmfiFMtime(rpmfi fi)
Return current file modify time from file info set iterator.
fdDup
FD_t fdDup(int fdno)
Ferror
int Ferror(FD_t fd)
ferror(3) clone.
rpmfiArchiveHasContent
int rpmfiArchiveHasContent(rpmfi fi)
Has current file content stored in the archive.
rpmfiFN
const char * rpmfiFN(rpmfi fi)
Return current file name from file info set iterator.
rstreq
static int rstreq(const char *s1, const char *s2)
Test for string equality.
Definition: rpmstring.h:113
headerFree
Header headerFree(Header h)
Dereference a header instance.
rpm_loff_t
uint64_t rpm_loff_t
Definition: rpmtypes.h:51
rpmfiles
struct rpmfiles_s * rpmfiles
Definition: rpmtypes.h:67
Fclose
int Fclose(FD_t fd)
fclose(3) clone.
rpmfiFNlink
uint32_t rpmfiFNlink(rpmfi fi)
Return (calculated) current file nlink count from file info set iterator.
write_file_content
static void write_file_content(struct archive *a, char *buf, rpmfi fi)
Definition: rpm2archive.c:43
rpmVSFlags
rpmFlags rpmVSFlags
Definition: rpmts.h:110
Fopen
FD_t Fopen(const char *path, const char *fmode)
fopen(3) clone.
headerGetString
const char * headerGetString(Header h, rpmTagVal tag)
Return a simple string tag from header.
rpmfiFGroup
const char * rpmfiFGroup(rpmfi fi)
Return current file group from file info set iterator.
RPMRC_NOTTRUSTED
Definition: rpmtypes.h:107
rpmfiFRdev
rpm_rdev_t rpmfiFRdev(rpmfi fi)
Return current file rdev from file info set iterator.
rpmfiNext
int rpmfiNext(rpmfi fi)
Return next file iterator index.
main
int main(int argc, char *argv[])
Definition: rpm2archive.c:177
process_package
static int process_package(rpmts ts, char *filename)
Definition: rpm2archive.c:61
mode
static int mode
Definition: rpmdb.c:21
rpmfiNewArchiveReader
rpmfi rpmfiNewArchiveReader(FD_t fd, rpmfiles files, int itype)
Get new file iterator for looping over the archive content.
_free
#define _free(_ptr)
Definition: system.h:89
_RPMVSF_NOSIGNATURES
#define _RPMVSF_NOSIGNATURES
Definition: rpmts.h:118
rpmtsFree
rpmts rpmtsFree(rpmts ts)
Destroy transaction set, closing the database as well.
rpmtsSetVSFlags
rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
Set verify signatures flag(s).
rpmts
struct rpmts_s * rpmts
The main types involved in transaction manipulation.
Definition: rpmtypes.h:63
RPMERR_ITER_END
Definition: rpmarchive.h:14
system.h
Some misc low-level API.
RPMRC_NOTFOUND
Definition: rpmtypes.h:105
rpmfiFSize
rpm_loff_t rpmfiFSize(rpmfi fi)
Return current file size from file info set iterator.
RPMVSF_NOHDRCHK
Definition: rpmts.h:95
__progname
#define __progname
Definition: system.h:98
fill_archive_entry
static void fill_archive_entry(struct archive *a, struct archive_entry *entry, rpmfi fi)
Definition: rpm2archive.c:21
_RPMVSF_NODIGESTS
#define _RPMVSF_NODIGESTS
Definition: rpmts.h:112
RPMRC_OK
Definition: rpmtypes.h:104
rpmfiFMode
rpm_mode_t rpmfiFMode(rpmfi fi)
Return current file mode from file info set iterator.
rpmfiFLink
const char * rpmfiFLink(rpmfi fi)
Return current file linkto (i.e.
rpmtsCreate
rpmts rpmtsCreate(void)
Create an empty transaction set.
rpmfiBN
const char * rpmfiBN(rpmfi fi)
Return current base name from file info set iterator.
rpmfiDN
const char * rpmfiDN(rpmfi fi)
Return current directory name from file info set iterator.
rpmfiFUser
const char * rpmfiFUser(rpmfi fi)
Return current file owner from file info set iterator.
rpm_mode_t
uint16_t rpm_mode_t
Definition: rpmtypes.h:53
RPMTAG_PAYLOADCOMPRESSOR
Definition: rpmtag.h:195
RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST
Definition: rpmfiles.h:153
Header
struct headerToken_s * Header
RPM header and data retrieval types.
Definition: rpmtypes.h:24