File rpm2archive.diff of Package rpm

--- tools/CMakeLists.txt.orig	2025-03-07 13:25:15.637092178 +0000
+++ tools/CMakeLists.txt	2025-03-07 13:26:53.764950409 +0000
@@ -41,7 +41,6 @@ if (READLINE_FOUND)
 endif()
 
 add_executable(rpm2archive rpm2archive.c)
-target_link_libraries(rpm2archive PRIVATE PkgConfig::LIBARCHIVE)
 install(TARGETS rpm2archive)
 
 # Everything links to these
--- tools/rpm2archive.c.orig	2025-02-19 15:29:33.000000000 +0000
+++ tools/rpm2archive.c	2025-03-07 13:25:19.881086047 +0000
@@ -2,6 +2,14 @@
 
 #include "system.h"
 
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/mkdev.h>
+#elif defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#else
+#include <sys/types.h> /* already included from system.h */
+#endif
+
 #include <rpm/rpmlib.h>		/* rpmReadPackageFile .. */
 #include <rpm/rpmfi.h>
 #include <rpm/rpmstring.h>
@@ -12,8 +20,11 @@
 
 #include <popt.h>
 
+#if 0
 #include <archive.h>
 #include <archive_entry.h>
+#endif
+
 #include <unistd.h>
 #include <errno.h>
 #include <libgen.h>
@@ -36,6 +47,8 @@ static struct poptOption optionsTable[]
     POPT_TABLEEND
 };
 
+#if 0
+
 static void fill_archive_entry(struct archive_entry * entry, rpmfi fi,
 				char **hardlink)
 {
@@ -282,6 +295,540 @@ static int process_package(rpmts ts, con
     return rc;
 }
 
+#else
+
+static int do_fwrite(FD_t fdo, const void *p, size_t l)
+{
+    if (Fwrite(p, l, 1, fdo) != l) {
+	fprintf(stderr, "Error writing archive: %s\n", Fstrerror(fdo));
+	return RPMRC_FAIL;
+    }
+    return RPMRC_OK;
+}
+
+static int do_fwrite_content(FD_t fdo, 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) {
+	    fprintf(stderr, "Error reading file from rpm payload\n");
+	    break;
+	}
+	if (do_fwrite(fdo, buf, len)) {
+	    fprintf(stderr, "Error writing archive: %s\n", Fstrerror(fdo));
+	    break;
+	}
+	left -= len;
+    }
+    return (left > 0);
+}
+
+/* cpio support */
+
+static inline void write_cpio_entry_num(unsigned char *p, unsigned long val)
+{
+    char space[64];
+    sprintf(space, "%8.8lx", val);
+    memcpy(p, space, 8);
+}
+
+static int write_cpio_entry(FD_t fdo, rpmfi fi, const char *filename, struct stat *st, const char *flink, const char *hlink, char *buf)
+{
+    unsigned char cpioh[110];
+    memcpy(cpioh, "070701", 6);
+    if (!fi) {
+	memset(cpioh + 6, '0', sizeof(cpioh) - 6);
+	write_cpio_entry_num(cpioh + 38, 1);
+	write_cpio_entry_num(cpioh + 94, 11);
+	if (do_fwrite(fdo, cpioh, sizeof(cpioh)))
+	    return RPMRC_FAIL;
+	if (do_fwrite(fdo, "TRAILER!!!\0\0\0", 11 + 3))
+	    return RPMRC_FAIL;
+	return RPMRC_OK;
+    }
+    if (st->st_size > UINT32_MAX) {
+	fprintf(stderr, "Warning: file too large for format, skipping: %s\n", filename);
+	return RPMRC_OK;
+    }
+    size_t fnl = strlen(filename);
+    write_cpio_entry_num(cpioh + 6, st->st_ino);
+    write_cpio_entry_num(cpioh + 14, st->st_mode);
+    write_cpio_entry_num(cpioh + 22, st->st_uid);
+    write_cpio_entry_num(cpioh + 30, st->st_gid);
+    write_cpio_entry_num(cpioh + 38, st->st_nlink);
+    write_cpio_entry_num(cpioh + 46, st->st_mtime);
+    write_cpio_entry_num(cpioh + 54, st->st_size);
+    write_cpio_entry_num(cpioh + 62, major(st->st_dev));
+    write_cpio_entry_num(cpioh + 70, minor(st->st_dev));
+    write_cpio_entry_num(cpioh + 78, major(st->st_rdev));
+    write_cpio_entry_num(cpioh + 86, minor(st->st_rdev));
+    write_cpio_entry_num(cpioh + 94, fnl + 1);
+    write_cpio_entry_num(cpioh + 102, 0);
+    if (do_fwrite(fdo, cpioh, sizeof(cpioh)))
+	return RPMRC_FAIL;
+    if (do_fwrite(fdo, filename, fnl + 1))
+	return RPMRC_FAIL;
+    fnl = (110 + fnl + 1) & 3;
+    if (fnl && do_fwrite(fdo, "\0\0\0", 4 - fnl))
+	return RPMRC_FAIL;
+    if (S_ISLNK(st->st_mode)) {
+	if (st->st_size != strlen(flink))
+	    return RPMRC_FAIL;
+	if (do_fwrite(fdo, flink, st->st_size))
+	    return RPMRC_FAIL;
+    } else if (S_ISREG(st->st_mode)) {
+        if (st->st_size && do_fwrite_content(fdo, buf, fi))
+	    return RPMRC_FAIL;
+    } else {
+	return RPMRC_OK;
+    }
+    fnl = (st->st_size) & 3;
+    if (fnl && do_fwrite(fdo, "\0\0\0", 4 - fnl))
+	return RPMRC_FAIL;
+    return RPMRC_OK;
+}
+
+/* pax support */
+
+static void add_pax_attrib(char **paxbuf, const char *pax, const char *val)
+{
+    size_t ten, len = 1 + strlen(pax) + 1 + strlen(val) + 1;
+    for (ten = 1; ten <= len; ten *= 10)
+	len++;
+    if (*paxbuf)
+        *paxbuf = realloc(*paxbuf, strlen(*paxbuf) + len + 1);
+    else {
+        *paxbuf = xmalloc(len + 1);
+	**paxbuf = 0;
+    }
+    sprintf(*paxbuf + strlen(*paxbuf), "%llu %s=%s\n", (unsigned long long)len, pax, val);
+}
+
+static void set_pax_entry_num_base256(unsigned char *p, unsigned long long val, int size)
+{
+    /* use base-256 encoding */
+    unsigned char *pe = p + size;
+    for (; pe > p; val >>= 8)
+	*pe-- = (unsigned char)(val & 255);
+    *p |= 0x80;
+}
+
+static inline void set_pax_entry_num(unsigned char *p, unsigned long long val, int size, char *pax, char **paxbuf)
+{
+    char space[64];
+    int sz = size == 12 ? size - 1 : size - 2;
+    if (paxbuf && val >= (unsigned long long)1 << (sz * 3)) {
+        /* add pax header */
+	sprintf(space, "%llu", val);
+        add_pax_attrib(paxbuf, pax, space);
+    }
+    if (val >= (unsigned long long)1 << (size * 3)) {
+	set_pax_entry_num_base256(p, val, size);
+	return;
+    }
+    sprintf(space, "%0*llo ", sz, val);
+    memcpy(p, space, size);
+}
+
+static int pax_is_ascii(const char *val)
+{
+    for (; *val; val++)
+	if (*(const unsigned char *)val >= 0x80)
+	    return 0;
+    return 1;
+}
+
+static inline void set_pax_entry_str(unsigned char *p, const char *val, int size, char *pax, char **paxbuf)
+{
+    size_t l = strlen(val);
+    if (paxbuf && (l > size || !pax_is_ascii(val)))
+        add_pax_attrib(paxbuf, pax, val);
+    memcpy(p, val, l < size ? l : size);
+}
+
+static void set_pax_path_mangle(unsigned char *paxh, const char *filename, const char *insert)
+{
+    size_t l = strlen(filename);
+    size_t ilen = insert ? strlen(insert) + 1 : 0;
+    const char *p, *p2, *bn;
+    int isdir = 0;
+    /* strip trailing '/' and '/.' components */
+    while (l && (filename[l - 1] == '/' || (filename[l - 1] == '.' && l > 1 && filename[l - 2] == '/'))) {
+	l--;
+	isdir = 1;
+    }
+    if (ilen) {
+	isdir = 0;		/* no trailing slash for a PaxHeader */
+	if (l == 0) {
+	    filename = "/rootdir";
+	    l = 8;
+	} else if (l == 1 && filename[0] == '.') {
+	    filename = "currentdir";
+	    l = 10;
+	} else if (l == 2 && filename[0] == '.' && filename[1] == '.') {
+	    filename = "parrentdir";
+	    l = 10;
+	}
+    }
+    /* find the basename */
+    bn = filename + l;
+    while (bn > filename && bn[-1] != '/')
+	bn--;
+    /* truncate basename (we use 99 like libarchive so we can add a '/' if the prefix is empty) */
+    l -= bn - filename;
+    if (l > 99 - (ilen + isdir))
+	l = 99 - (ilen + isdir);
+    /* calculate prefix */
+    if (bn - filename <= 100 - (l + ilen + isdir)) {
+	p = filename;		/* no need for a prefix */
+    } else {
+	p = bn - filename > 155 ? filename + 155 : bn;
+	while (p > filename && *p != '/')
+	    p--;
+	/* move as much of the prefix into name as possible */
+        if (p > filename && bn - p < 99 - (l + ilen + isdir)) {
+	    p2 = strchr(bn - (99 - (l + ilen + isdir)), '/');
+	    if (p2 && p2 < p)
+		p = p2;
+	}
+    }
+    /* copy the prefix */
+    if (p != filename) {
+	memcpy(paxh + 345, filename, p - filename);
+	p++;	/* skip the '/' */
+    }
+    /* copy rest of the dir */
+    p2 = p + (99 - (l + ilen + isdir)) > bn ? bn : p + (99 - (l + ilen + isdir));
+    while (p2 > p && *p2 != '/')
+	p2--;
+    if (p2 < bn && *p2 == '/')
+	p2++;		/* always fits as we used 99 as size limit above */
+    memcpy(paxh, p, p2 - p);
+    /* copy the insert */
+    if (ilen) {
+	memcpy(paxh + (p2 - p), insert, ilen);
+	paxh[p2 - p + ilen - 1] = '/';
+    }
+    /* copy the basename */
+    memcpy(paxh + (p2 - p) + ilen, bn, l);
+    if (isdir)
+	paxh[p2 - p + ilen + l] = '/';
+}
+
+static int set_pax_path(unsigned char *paxh, const char *filename)
+{
+    size_t l = strlen(filename);
+    if (l <= 100) {
+	memcpy(paxh, filename, l);
+	return 0;
+    }
+    const char *p = strchr(filename + l - 100 - 1, '/');
+    if (p == filename)
+	p = strchr(filename + 1, '/');
+    if (p && p[1] && p - filename <= 155) {
+	memcpy(paxh, p + 1, l - (p + 1 - filename));
+	memcpy(paxh + 345, filename, p - filename);
+	return 0;
+    }
+    set_pax_path_mangle(paxh, filename, NULL);
+    return 1;
+}
+
+static int write_pax_entry_pax(FD_t fdo, rpmfi fi, const char *filename, struct stat *st, char *paxbuf);
+
+static int write_pax_entry(FD_t fdo, rpmfi fi, const char *filename, struct stat *st, const char *flink, const char *hlink, char *buf)
+{
+    unsigned char paxh[512];
+    int tartype = -1;
+    rpm_loff_t size = 0;
+
+    memset(paxh, 0, sizeof(paxh));
+    if (!fi) {
+	if (do_fwrite(fdo, paxh, sizeof(paxh)))
+	    return RPMRC_FAIL;
+	if (do_fwrite(fdo, paxh, sizeof(paxh)))
+	    return RPMRC_FAIL;
+	return RPMRC_OK;
+    }
+    if (filename == NULL && flink)
+	tartype = 'x';
+    else if (S_ISREG(st->st_mode))
+	tartype = st->st_nlink > 1 && !rpmfiArchiveHasContent(fi) ? '1' : '0';
+    else if (S_ISLNK(st->st_mode))
+	tartype = '2';
+    else if (S_ISCHR(st->st_mode))
+	tartype = '3';
+    else if (S_ISBLK(st->st_mode))
+	tartype = '4';
+    else if (S_ISDIR(st->st_mode))
+	tartype = '5';
+    else if (S_ISFIFO(st->st_mode))
+	tartype = '6';
+    if (tartype == -1) {
+	fprintf(stderr, "Warning: unsupported file type, skipping: %s\n", filename);
+	return RPMRC_OK;
+    }
+    if (tartype == '5') {
+	size_t l = strlen(filename);
+	if (!l || filename[l - 1] != '/') {
+	    char *dirfilename = rstrscat(NULL, filename, "/", NULL);
+	    int r = write_pax_entry(fdo, fi, dirfilename, st, flink, hlink, buf);
+	    _free(dirfilename);
+	    return r;
+	}
+    }
+    if (tartype == '0' ||  tartype == '1')
+	size =  rpmfiFSize(fi);
+    else if (tartype == 'x')
+	size = (rpm_loff_t)strlen(buf);
+
+    /* fill entry header */
+    char *paxbuf = NULL;
+    char **paxbufp = tartype == 'x' ? NULL : &paxbuf;
+    if (tartype == 'x') {
+	set_pax_path_mangle(paxh, flink, "PaxHeader");
+    } else {
+	if (set_pax_path(paxh, filename) || !pax_is_ascii(filename))
+	    add_pax_attrib(paxbufp, "path", filename);
+    }
+    set_pax_entry_num(paxh + 100, st->st_mode & 07777, 8, NULL, NULL);
+    set_pax_entry_num(paxh + 108, st->st_uid, 8, "uid", paxbufp);
+    set_pax_entry_num(paxh + 116, st->st_gid, 8, "gid", paxbufp);
+    set_pax_entry_num(paxh + 124, size, 12, "size", paxbufp);
+    set_pax_entry_num(paxh + 136, st->st_mtime, 12, "mtime", paxbufp);
+    memset(paxh + 148, ' ', 8);
+    paxh[156] = tartype;
+    if (tartype == '1' || tartype == '2')
+        set_pax_entry_str(paxh + 157, tartype == '1' ? hlink : flink, 100, "linkpath", paxbufp);
+    memcpy(paxh + 257, "ustar\00000", 8);
+    set_pax_entry_str(paxh + 265, rpmfiFUser(fi), 32, "user", paxbufp);
+    set_pax_entry_str(paxh + 297, rpmfiFGroup(fi), 32, "group", paxbufp);
+    set_pax_entry_num(paxh + 329, major(st->st_rdev), 8, "SCHILY.devmajor", paxbufp);
+    set_pax_entry_num(paxh + 337, minor(st->st_rdev), 8, "SCHILY.devminor", paxbufp);
+    int i, checksum = 0;
+    for (i = 0; i < 512; i++)
+	checksum += paxh[i];
+    set_pax_entry_num(paxh + 148, checksum, 8, NULL, NULL);
+    paxh[148 + 6] = 0;
+    paxh[148 + 7] = ' ';
+    /* write pax header if we need it */
+    if (paxbuf) {
+	int r = write_pax_entry_pax(fdo, fi, filename, st, paxbuf);
+	free(paxbuf);
+	if (r)
+	    return RPMRC_FAIL;
+    }
+    /* write entry header */
+    if (do_fwrite(fdo, paxh, 512))
+	return RPMRC_FAIL;
+    if (tartype != '0' && tartype != 'x')
+	return RPMRC_OK;	/* no content for those types */
+    /* write content */
+    if (tartype == '0' && size && do_fwrite_content(fdo, buf, fi))
+	return RPMRC_FAIL;
+    if (tartype == 'x' && size && do_fwrite(fdo, buf, size))
+	return RPMRC_FAIL;
+    /* write padding */
+    size &= 511;
+    if (size) {
+	memset(paxh, 0, sizeof(paxh));
+	if (do_fwrite(fdo, paxh, 512 - size))
+	    return RPMRC_FAIL;
+    }
+    return RPMRC_OK;
+}
+
+static int write_pax_entry_pax(FD_t fdo, rpmfi fi, const char *filename, struct stat *st, char *paxbuf)
+{
+    /* tweak stat data and filename */
+    struct stat paxst = *st;
+    paxst.st_size = strlen(paxbuf);
+    paxst.st_mode = paxst.st_mode & 0777;
+    if (paxst.st_uid >= (1 << 18))
+	paxst.st_uid = (1 << 18) - 1;
+    if (paxst.st_gid >= (1 << 18))
+	paxst.st_gid = (1 << 18) - 1;
+    if (paxst.st_mtime < 0)
+	paxst.st_mtime = 0;
+    if ((unsigned long long)paxst.st_mtime >= 1ULL << 33)
+	paxst.st_mtime = (time_t)((1ULL << 33) - 1);
+    return write_pax_entry(fdo, fi, NULL, &paxst, filename, NULL, paxbuf);
+}
+
+static int process_package(rpmts ts, const char * filename)
+{
+    FD_t fdi;
+    FD_t gzdi;
+    FD_t fdo;
+    Header h;
+    int rc = 0;
+    char * rpmio_flags = NULL;
+    int iscpio = 0;
+
+    if (!strcmp(filename, "-")) {
+        if(isatty(STDIN_FILENO)) {
+            fprintf(stderr, "Error: missing input RPM package\n");
+            exit(EXIT_FAILURE);
+        }
+	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);
+    }
+
+    if (rstreq(format, "pax")) {
+	iscpio = 0;
+    } else if (rstreq(format, "cpio")) {
+	iscpio = 1;
+    } else {
+	fprintf(stderr, "Error: Format %s is not supported\n", format);
+	exit(EXIT_FAILURE);
+    }
+
+    if (!isatty(STDOUT_FILENO)) {
+        fdo = fdDup(STDOUT_FILENO);
+    } else {
+        if (!strcmp(filename, "-")) {
+	    fprintf(stderr, "Error: refusing to output archive data to a terminal.\n");
+	    exit(EXIT_FAILURE);
+	}
+	char * outname;
+	if (urlIsURL(filename)) {
+	    const char * fname = strrchr(filename, '/');
+	    if (fname != NULL) {
+		fname++;
+	    } else {
+		fname = filename;
+	    }
+	    outname = rstrscat(NULL, fname, NULL);
+	} else {
+	    outname = rstrscat(NULL, filename, NULL);
+	}
+	if (compress) {
+	    outname = rstrscat(&outname, ".tgz", NULL);
+	} else {
+	    outname = rstrscat(&outname, ".tar", NULL);
+	}
+        fdo = Fopen(outname, "w.ufdio");
+	if (!fdo) {
+	    fprintf(stderr, "Error: Can't open output file: %s\n", outname);
+	    exit(EXIT_FAILURE);
+	}
+	_free(outname);
+    }
+    if (compress && fdo)
+	fdo = Fdopen(fdo, "w.gzdio");
+    if (!fdo) {
+	fprintf(stderr, "Error: Can't setup output file\n");
+	exit(EXIT_FAILURE);
+    }
+
+    char * buf = (char *)xmalloc(BUFSIZE);
+    char * hardlink = NULL;
+
+    rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
+    rpmfi fi = rpmfiNewArchiveReader(gzdi, files, iscpio ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);
+
+    while ((rc = rpmfiNext(fi)) >= 0) {
+	struct stat st;
+	const char *dn, *flink;
+	char *filename;
+	if (rpmfiStat(fi, 0, &st)) {
+	    break;
+	}
+	dn = rpmfiDN(fi);
+	if (!strcmp(dn, "")) dn = "/";
+	filename = rstrscat(NULL, ".", dn, rpmfiBN(fi), NULL);
+	flink = S_ISLNK(st.st_mode) ? rpmfiFLink(fi) : NULL;
+	if (st.st_nlink > 1 && !iscpio) {
+	    if (rpmfiArchiveHasContent(fi)) {
+		/* hardlink sizes are special, see rpmfiStat() */
+		_free(hardlink);
+		hardlink = xstrdup(filename);
+	    }
+	}
+        if (iscpio)
+	    rc = write_cpio_entry(fdo, fi, filename, &st, flink, st.st_nlink > 1 ? hardlink : NULL, buf);
+	else
+	    rc = write_pax_entry(fdo, fi, filename, &st, flink, st.st_nlink > 1 ? hardlink : NULL, buf);
+	_free(filename);
+	if (rc == RPMRC_FAIL)
+	    break;
+    }
+    /* End of iteration is not an error, everything else is */
+    if (rc == RPMERR_ITER_END) {
+	rc = 0;
+    } else {
+	rc = 1;
+    }
+
+    /* write trailer */
+    if (!rc) {
+        if (iscpio)
+	    rc = write_cpio_entry(fdo, NULL, NULL, NULL, NULL, NULL, buf);
+	else
+	    rc = write_pax_entry(fdo, NULL, NULL, NULL, NULL, NULL, buf);
+	rc = rc == RPMRC_FAIL ? 1 : 0;
+    }
+
+    if (Fclose(fdo) && !rc) {
+	fprintf(stderr, "Error writing archive\n");
+	rc = 1;
+    }
+
+    _free(hardlink);
+
+    Fclose(gzdi);	/* XXX gzdi == fdi */
+    buf = _free(buf);
+    rpmfilesFree(files);
+    rpmfiFree(fi);
+    headerFree(h);
+    return rc;
+}
+#endif
+
+
 int main(int argc, char *argv[])
 {
     int rc = 0;
openSUSE Build Service is sponsored by