diff --git a/0001-Add-option-to-set-mtime-of-files-in-rpms.patch b/0001-Add-option-to-set-mtime-of-files-in-rpms.patch deleted file mode 100644 index 4214f3f..0000000 --- a/0001-Add-option-to-set-mtime-of-files-in-rpms.patch +++ /dev/null @@ -1,122 +0,0 @@ -From fc04a1bde1941d2c61a9e33e55c5c492327674ba Mon Sep 17 00:00:00 2001 -From: Jan Zerebecki -Date: Thu, 15 Feb 2024 09:57:35 +0100 -Subject: [PATCH 1/3] Add option to set mtime of files in rpms - -to SOURCE_DATE_EPOCH. - -For backwards compatibility the option clamp / limit the maximum mtime -is retained. - -Setting it ouright avoids problems with an incorrectly older clock. It -also avoids problems with build scrips that incorrectly change file -mtimes when SOURCE_DATE_EPOCH_MTIME is in use. - -mtimes are required to increase with new versions and releases -of an rpm with the same name, as rsync without --checksum and similar -tools would get confused if the content changes without newer mtime. - -If SOURCE_DATE_EPOCH_MTIME is set use it instead for file modification time -stamps. It is supposed to be newer. This can be used if we might want to -compare if the file content remains the same when a build dependency -changes while a build script embeds SOURCE_DATE_EPOCH in the file -content. - -This can be used to support automatic rebuilds. Normally automatic -rebuilds work, but together with reproducible builds an undesirable -situation may occur. If a build e.g. embeds SOURCE_DATE_EPOCH in the -output, then the output changes every time such a rebuild happens, which -can be very often. This is to be avoided as updating packages without -necessity is too expensive. ---- - build/files.c | 33 ++++++++++++++++++++++++++++----- - docs/manual/buildprocess.md | 5 +++-- - 2 files changed, 31 insertions(+), 7 deletions(-) - -diff --git a/build/files.c b/build/files.c -index c403c806e..cec7999ca 100644 ---- a/build/files.c -+++ b/build/files.c -@@ -1033,14 +1033,34 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) - rpm_loff_t totalFileSize = 0; - Header h = pkg->header; /* just a shortcut */ - int override_date = 0; -+ int set_mtime = 0; - time_t source_date_epoch = 0; - char *srcdate = getenv("SOURCE_DATE_EPOCH"); -+ char *msrcdate = getenv("SOURCE_DATE_EPOCH_MTIME"); - -- /* Limit the maximum date to SOURCE_DATE_EPOCH if defined -- * similar to the tar --clamp-mtime option -+ /* If SOURCE_DATE_EPOCH_MTIME is set use it for file modification time -+ * stamps, it is supposed to be newer. This can be used if we might want to -+ * compare if the file content remains the same when a build dependency -+ * changes while a build script embeds SOURCE_DATE_EPOCH in the file -+ * content. mtimes are required to increase with new versions and releases -+ * of an rpm with the same name, as rsync without --checksum and similar -+ * tools would get confused if the content changes without newer mtime. */ -+ if (msrcdate != NULL) { -+ srcdate = msrcdate; -+ } -+ -+ /* Set the file mtime to SOURCE_DATE_EPOCH it if requested to make the -+ * resulting rpm reproducible. - * https://reproducible-builds.org/specs/source-date-epoch/ -+ * -+ * For backwards compatibility clamp / limit the maximum mtime if requested -+ * similar the tar --clamp-mtime option. Setting it ouright avoids problems -+ * with an incorrectly older clock. It also avoids problems with build -+ * scrips that incorrectly change file mtimes when SOURCE_DATE_EPOCH_MTIME -+ * is in use. - */ -- if (srcdate && rpmExpandNumeric("%{?clamp_mtime_to_source_date_epoch}")) { -+ if (srcdate && (rpmExpandNumeric("%{?clamp_mtime_to_source_date_epoch}") -+ || rpmExpandNumeric("%{?set_mtime_to_source_date_epoch}"))) { - char *endptr; - errno = 0; - source_date_epoch = strtol(srcdate, &endptr, 10); -@@ -1049,6 +1069,9 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) - fl->processingFailed = 1; - } - override_date = 1; -+ if (rpmExpandNumeric("%{?set_mtime_to_source_date_epoch}")) { -+ set_mtime = 1; -+ } - } - - /* -@@ -1191,8 +1214,8 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc) - totalFileSize += flp->fl_size; - } - } -- -- if (override_date && flp->fl_mtime > source_date_epoch) { -+ -+ if (override_date && (flp->fl_mtime > source_date_epoch || set_mtime)) { - flp->fl_mtime = source_date_epoch; - } - /* -diff --git a/docs/manual/buildprocess.md b/docs/manual/buildprocess.md -index 1ceb47a7e..64cd35626 100644 ---- a/docs/manual/buildprocess.md -+++ b/docs/manual/buildprocess.md -@@ -94,13 +94,14 @@ Macro name | Description - `%_build_pkgcheck` | Progam to run on each generated binary package - `%_build_pkcheck_set` | Program to run on the generated binary package set - --### Reproducability -+### Reproducibility - - Macro name | Description - --------------------------------------|----------- - `%source_date_epoch_from_changelog` | Set `SOURCE_DATE_EPOCH` from latest `%changelog` entry - `%use_source_date_epoch_as_buildtime` | Set package BuildTime to `SOURCE_DATE_EPOCH` --`%clamp_mtime_to_source_date_epoch` | Ensure file timestamps are not newer than `SOURCE_DATE_EPOCH` -+`%set_mtime_to_source_date_epoch` | Set file modification timestamps to `SOURCE_DATE_EPOCH_MTIME` or as fallback to `SOURCE_DATE_EPOCH` -+`%clamp_mtime_to_source_date_epoch` | You should use the above instead, it is for backwards compatibility only. Ensure file timestamps are not newer than `SOURCE_DATE_EPOCH` - - ### Vendor defaults - --- -2.30.2 - diff --git a/buildsys.diff b/buildsys.diff new file mode 100644 index 0000000..7f0a405 --- /dev/null +++ b/buildsys.diff @@ -0,0 +1,12 @@ +--- build/parseSpec.c.orig 2025-02-13 13:20:21.075462279 +0000 ++++ build/parseSpec.c 2025-02-13 13:15:42.447942795 +0000 +@@ -1429,7 +1429,8 @@ static rpmRC parseSpecParts(rpmSpec spec + /* rpmGlob returns files sorted */ + if (rpmGlob(pattern, &argc, &argv) == 0) { + for (int i = 0; i < argc; i++) { +- rpmlog(RPMLOG_NOTICE, "Reading %s\n", argv[i]); ++ if (stage != PARSE_BUILDSYS) ++ rpmlog(RPMLOG_NOTICE, "Reading %s\n", argv[i]); + pushOFI(spec, argv[i]); + snprintf(spec->fileStack->readBuf, spec->fileStack->readBufLen, + "# Spec part read from %s\n\n", argv[i]); diff --git a/macrosin.diff b/macrosin.diff index e8c9eae..7f9e638 100644 --- a/macrosin.diff +++ b/macrosin.diff @@ -1,16 +1,6 @@ ---- macros.in.orig 2024-12-16 12:48:44.110837972 +0000 -+++ macros.in 2024-12-16 12:52:32.014378635 +0000 -@@ -118,6 +118,9 @@ - # The directory where sources/patches will be unpacked and built. - %_builddir %{_topdir}/BUILD - -+# The build root where built files will be installed into -+%buildroot %{_builddir}/%{NAME}-%{VERSION}-build/BUILDROOT -+ - # The interpreter used for build scriptlets. - %_buildshell /bin/sh - -@@ -163,6 +166,7 @@ +--- macros.in.orig 2025-02-12 13:23:21.868124201 +0000 ++++ macros.in 2025-02-12 13:23:58.436059109 +0000 +@@ -163,6 +163,7 @@ %{?_unique_debug_names:--unique-debug-suffix "-%{VERSION}-%{RELEASE}.%{_arch}"} \\\ %{?_unique_debug_srcs:--unique-debug-src-base "%{name}-%{VERSION}-%{RELEASE}.%{_arch}"} \\\ %{?_find_debuginfo_dwz_opts} \\\ @@ -18,7 +8,7 @@ %{?_find_debuginfo_opts} \\\ %{?_debugsource_packages:-S debugsourcefiles.list} \\\ "%{builddir}/%{?buildsubdir}"\ -@@ -216,7 +220,8 @@ Supplements: (%{name} = %{version}-%{r +@@ -216,7 +217,8 @@ Supplements: (%{name} = %{version}-%{r %files langpack-%{1}\ %{nil} @@ -28,7 +18,7 @@ %_defaultlicensedir %{_datadir}/licenses # Following macros for filtering auto deps must not be used in spec files. -@@ -275,7 +280,8 @@ Supplements: (%{name} = %{version}-%{r +@@ -275,7 +277,8 @@ Supplements: (%{name} = %{version}-%{r %_tmppath %{_var}/tmp # Path to top of build area. @@ -38,7 +28,7 @@ #============================================================================== # ---- Optional rpmrc macros. -@@ -366,7 +372,7 @@ Supplements: (%{name} = %{version}-%{r +@@ -366,7 +369,7 @@ Supplements: (%{name} = %{version}-%{r # "w.ufdio" uncompressed # #%_source_payload w9.gzdio @@ -47,7 +37,7 @@ # Algorithm to use for generating file checksum digests on build. # If not specified or 0, MD5 is used. -@@ -476,6 +482,19 @@ Supplements: (%{name} = %{version}-%{r +@@ -476,6 +479,19 @@ Supplements: (%{name} = %{version}-%{r # #%_include_minidebuginfo 1 @@ -67,7 +57,7 @@ # # Include a .gdb_index section in the .debug files. # Requires _enable_debug_packages and gdb-add-index installed. -@@ -508,39 +527,39 @@ Supplements: (%{name} = %{version}-%{r +@@ -508,39 +524,39 @@ Supplements: (%{name} = %{version}-%{r # Same as for "separate" but if the __debug_package global is set then # the -debuginfo package will have a compatibility link for the main # ELF /usr/lib/debug/.build-id/xx/yyy -> /usr/lib/.build-id/xx/yyy @@ -114,7 +104,7 @@ # # Use internal dependency generator rather than external helpers? -@@ -559,6 +578,7 @@ Supplements: (%{name} = %{version}-%{r +@@ -559,6 +575,7 @@ Supplements: (%{name} = %{version}-%{r %__find_requires %{_rpmconfigdir}/find-requires #%__find_conflicts ??? #%__find_obsoletes ??? @@ -122,7 +112,7 @@ # # Path to file attribute classifications for automatic dependency -@@ -980,7 +1000,7 @@ Supplements: (%{name} = %{version}-%{r +@@ -980,7 +997,7 @@ Supplements: (%{name} = %{version}-%{r %_build_vendor %{_host_vendor} %_build_os %{_host_os} %_host @host@ @@ -131,7 +121,7 @@ %_host_cpu @host_cpu@ %_host_vendor @host_vendor@ %_host_os @host_os@ -@@ -1105,11 +1125,13 @@ Supplements: (%{name} = %{version}-%{r +@@ -1105,11 +1122,13 @@ Supplements: (%{name} = %{version}-%{r #------------------------------------------------------------------------------ # arch macro for all supported 32-bit ARM processors diff --git a/mtime_policy_set.diff b/mtime_policy_set.diff new file mode 100644 index 0000000..99386d9 --- /dev/null +++ b/mtime_policy_set.diff @@ -0,0 +1,34 @@ +--- build/files.c.orig 2025-02-12 13:27:08.131721537 +0000 ++++ build/files.c 2025-02-12 13:32:28.371151422 +0000 +@@ -1049,10 +1049,10 @@ static void genCpioListAndHeader(FileLis + } + } + +- if (!strcmp(mtime_policy_str, "clamp_to_buildtime")) { ++ if (!strcmp(mtime_policy_str, "clamp_to_buildtime") || !strcmp(mtime_policy_str, "set_to_buildtime")) { + mtime_clamp = spec->buildTime; +- override_date = 1; +- } else if (!strcmp(mtime_policy_str, "clamp_to_source_date_epoch")) { ++ override_date = mtime_policy_str[0] == 's' ? 2 : 1; ++ } else if (!strcmp(mtime_policy_str, "clamp_to_source_date_epoch") || !strcmp(mtime_policy_str, "set_to_source_date_epoch")) { + /* Limit the maximum date to SOURCE_DATE_EPOCH if defined + * similar to the tar --clamp-mtime option + * https://reproducible-builds.org/specs/source-date-epoch/ +@@ -1065,7 +1065,7 @@ static void genCpioListAndHeader(FileLis + rpmlog(RPMLOG_ERR, _("unable to parse %s=%s\n"), "SOURCE_DATE_EPOCH", srcdate); + fl->processingFailed = 1; + } +- override_date = 1; ++ override_date = mtime_policy_str[0] == 's' ? 2 : 1; + } + } else if (*mtime_policy_str) { + rpmlog(RPMLOG_WARNING, +@@ -1214,7 +1214,7 @@ static void genCpioListAndHeader(FileLis + } + } + +- if (override_date && flp->fl_mtime > mtime_clamp) { ++ if (override_date && (flp->fl_mtime > mtime_clamp || override_date == 2)) { + flp->fl_mtime = mtime_clamp; + } + /* diff --git a/rpm.changes b/rpm.changes index 6db9abc..c87dd45 100644 --- a/rpm.changes +++ b/rpm.changes @@ -1,3 +1,20 @@ +------------------------------------------------------------------- +Wed Feb 12 13:36:45 CET 2025 - mls@suse.de + +- make the rpm package not depend on libarchive + * move the rpmuncompress tool to rpm-build + * rewrite rpm2archive to not use libarchive for cpio/tar writing + * new patch: rpm2archive.diff +- revert buildroot macro setting that did more harm than good +- add set_to_buildtime and set_to_source_date_epoch mtime policy + support + * new patch: mtime_policy_set.diff +- drop unused 0001-Add-option-to-set-mtime-of-files-in-rpms.patch + patch +- do not output debug messages in rpmspec -q if a buildsystem is + used + * new patch: buildsys.diff + ------------------------------------------------------------------- Mon Feb 3 13:13:27 CET 2025 - mls@suse.de diff --git a/rpm.spec b/rpm.spec index 0627ac1..5449ef4 100644 --- a/rpm.spec +++ b/rpm.spec @@ -116,7 +116,6 @@ Patch135: selinux_transactional_update.patch Patch136: rpmsort_reverse.diff Patch138: canongnu.diff Patch139: cmake_python_version.diff -Patch140: 0001-Add-option-to-set-mtime-of-files-in-rpms.patch Patch141: 0002-log-build-time-if-it-is-set-from-SOURCE_DATE_EPOCH.patch Patch142: 0003-Error-out-on-a-missing-changelog-date.patch Patch150: unshare.diff @@ -124,6 +123,9 @@ Patch151: buildroot-symlink.diff Patch152: debugpackage.diff Patch153: nextfiles.diff Patch154: undefbuildroot.diff +Patch155: rpm2archive.diff +Patch156: mtime_policy_set.diff +Patch157: buildsys.diff Patch6464: auto-config-update-aarch64-ppc64le.diff BuildRoot: %{_tmppath}/%{name}-%{version}-build # @@ -241,11 +243,8 @@ rm -rf sqlite %patch -P 122 -P 123 %patch -P 131 -P 133 -P 134 -P 135 -P 136 -P 138 %patch -P 139 -%if 0 -%patch -P 140 -%endif %patch -P 141 -P 142 -%patch -P 150 -P 151 -P 152 -P 153 -P 154 +%patch -P 150 -P 151 -P 152 -P 153 -P 154 -P 155 -P 156 -P 157 %ifarch aarch64 ppc64le riscv64 loongarch64 %patch -P 6464 @@ -450,7 +449,6 @@ fi /usr/lib/rpm/rpmpopt-* /usr/lib/rpm/rpmrc /usr/lib/rpm/rpmsort - /usr/lib/rpm/rpmuncompress /usr/lib/rpm/rpmdump /usr/lib/rpm/suse /usr/lib/rpm/tgpg @@ -483,6 +481,7 @@ fi /usr/lib/rpm/rpm_macros_provides.sh /usr/lib/rpm/elfdeps /usr/lib/rpm/rpmdeps +/usr/lib/rpm/rpmuncompress /usr/bin/rpmspec /usr/lib/rpm/brp-* /usr/lib/rpm/check-* diff --git a/rpm2archive.diff b/rpm2archive.diff new file mode 100644 index 0000000..4e1e82f --- /dev/null +++ b/rpm2archive.diff @@ -0,0 +1,612 @@ +--- tools/CMakeLists.txt.orig 2025-02-13 09:56:00.257085875 +0000 ++++ tools/CMakeLists.txt 2025-02-13 09:56:11.433064235 +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 2024-10-07 09:35:46.000000000 +0000 ++++ tools/rpm2archive.c 2025-02-13 11:50:46.533098005 +0000 +@@ -2,6 +2,14 @@ + + #include "system.h" + ++#if defined(MAJOR_IN_MKDEV) ++#include ++#elif defined(MAJOR_IN_SYSMACROS) ++#include ++#else ++#include /* already included from system.h */ ++#endif ++ + #include /* rpmReadPackageFile .. */ + #include + #include +@@ -12,8 +20,11 @@ + + #include + ++#if 0 + #include + #include ++#endif ++ + #include + #include + #include +@@ -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;