SHA256
3
0
forked from pool/rpm
rpm/rpm2archive.diff

615 lines
18 KiB
Diff

--- tools/CMakeLists.txt.orig 2025-02-12 12:28:53.926181102 +0000
+++ tools/CMakeLists.txt 2025-02-12 12:31:14.961909654 +0000
@@ -40,11 +40,8 @@ if (READLINE_FOUND)
target_link_libraries(rpmlua PRIVATE PkgConfig::READLINE)
endif()
-if (WITH_ARCHIVE)
- add_executable(rpm2archive rpm2archive.c)
- target_link_libraries(rpm2archive PRIVATE PkgConfig::LIBARCHIVE)
- install(TARGETS rpm2archive)
-endif()
+add_executable(rpm2archive rpm2archive.c)
+install(TARGETS rpm2archive)
# Everything links to these
get_property(executables DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
@@ -60,12 +57,10 @@ foreach(cmd rpmverify rpmquery)
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${cmd} TYPE BIN)
endforeach()
-if (WITH_ARCHIVE)
- add_custom_target(rpm2cpio ALL COMMAND
- ${CMAKE_COMMAND} -E create_symlink rpm2archive rpm2cpio
- )
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rpm2cpio TYPE BIN)
-endif()
+add_custom_target(rpm2cpio ALL COMMAND
+ ${CMAKE_COMMAND} -E create_symlink rpm2archive rpm2cpio
+ )
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rpm2cpio TYPE BIN)
if (WITH_CXX)
set (cxx_sources
--- tools/rpm2archive.c.orig 2025-02-10 09:57:58.036626709 +0000
+++ tools/rpm2archive.c 2025-02-12 12:27:28.986344583 +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,542 @@ 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--;
+ if (bn == filename + 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 + (100 - (l + ilen + isdir)) > bn ? bn : p + (100 - (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;