|
|
2733a1 |
From e38a26f5d6050a5c72f7503c8664ca11623ed319 Mon Sep 17 00:00:00 2001
|
|
|
2733a1 |
From: Matteo Croce <teknoraver@meta.com>
|
|
|
2733a1 |
Date: Fri, 6 Dec 2024 07:45:17 +0100
|
|
|
2733a1 |
Subject: [PATCH] RPM with Copy on Write
|
|
|
2733a1 |
|
|
|
2733a1 |
This is part of https://fedoraproject.org/wiki/Changes/RPMCoW
|
|
|
2733a1 |
|
|
|
2733a1 |
The majority of changes are in two new programs:
|
|
|
2733a1 |
|
|
|
2733a1 |
= rpm2extents
|
|
|
2733a1 |
|
|
|
2733a1 |
Modeled as a 'stream processor'. It reads a regular .rpm file on stdin,
|
|
|
2733a1 |
and produces a modified .rpm file on stdout. The lead, signature and
|
|
|
2733a1 |
headers are preserved 1:1 to allow all the normal metadata inspection,
|
|
|
2733a1 |
signature verification to work as expected. Only the 'payload' is
|
|
|
2733a1 |
modified.
|
|
|
2733a1 |
|
|
|
2733a1 |
The primary motivation for this tool is to re-organize the payload as a
|
|
|
2733a1 |
sequence of raw file extents (hence the name). The files are organized
|
|
|
2733a1 |
by their digest identity instead of path/filename. If any digest is
|
|
|
2733a1 |
repeated, then the file is skipped/de-duped. Only regular files are
|
|
|
2733a1 |
represented. All other entries like directories, symlinks, devices are
|
|
|
2733a1 |
fully described in the headers and are omitted.
|
|
|
2733a1 |
|
|
|
2733a1 |
The files are padded so they start on `sysconf(_SC_PAGESIZE)` boundries
|
|
|
2733a1 |
to permit 'reflink' syscalls to work in the `reflink` plugin.
|
|
|
2733a1 |
|
|
|
2733a1 |
At the end of the file is a footer with 3 sections:
|
|
|
2733a1 |
|
|
|
2733a1 |
1. List of calculated digests of the input stream. This is used in
|
|
|
2733a1 |
`librepo` because the file *written* is a derivative, and not the
|
|
|
2733a1 |
same as the repo metadata describes. `rpm2extents` takes one or more
|
|
|
2733a1 |
positional arguments that described which digest algorithms are
|
|
|
2733a1 |
desired. This is often just `SHA256`. This program is only measuring
|
|
|
2733a1 |
and recording the digest - it does not express an opinion on whether
|
|
|
2733a1 |
the file is correct. Due to the API on most compression libraries
|
|
|
2733a1 |
directly reading the source file, the whole file digest is measured
|
|
|
2733a1 |
using a subprocess and pipes. I don't love it, but it works.
|
|
|
2733a1 |
2. Sorted List of file content digests + offset pairs. This is used in
|
|
|
2733a1 |
the plugin with a trivial binary search to locate the start of file
|
|
|
2733a1 |
content. The size is not needed because it's part of normal headers.
|
|
|
2733a1 |
3. (offset of 1., offset of 2., 8 byte MAGIC value) triple
|
|
|
2733a1 |
|
|
|
2733a1 |
= reflink plugin
|
|
|
2733a1 |
|
|
|
2733a1 |
Looks for the 8 byte magic value at the end of the rpm file. If present
|
|
|
2733a1 |
it alters the `RPMTAG_PAYLOADFORMAT` in memory to `clon`, and reads in
|
|
|
2733a1 |
the digest-> offset table.
|
|
|
2733a1 |
|
|
|
2733a1 |
`rpmPackageFilesInstall()` in `fsm.c` is
|
|
|
2733a1 |
modified to alter the enumeration strategy from
|
|
|
2733a1 |
`rpmfiNewArchiveReader()` to `rpmfilesIter()` if not `cpio`. This is
|
|
|
2733a1 |
needed because there is no cpio to enumerate. In the same function, if
|
|
|
2733a1 |
`rpmpluginsCallFsmFilePre()` returns `RPMRC_PLUGIN_CONTENTS` then
|
|
|
2733a1 |
`fsmMkfile()` is skipped as it is assumed the plugin did the work.
|
|
|
2733a1 |
|
|
|
2733a1 |
The majority of the work is in `reflink_fsm_file_pre()` - the per file
|
|
|
2733a1 |
hook for RPM plugins. If the file enumerated in
|
|
|
2733a1 |
`rpmPackageFilesInstall()` is a regular file, this function will look up
|
|
|
2733a1 |
the offset in the digest->offset table and will try to reflink it, then
|
|
|
2733a1 |
fall back to a regular copy. If reflinking does work: we will have
|
|
|
2733a1 |
reflinked a whole number of pages, so we truncate the file to the
|
|
|
2733a1 |
expected size. Therefore installing most files does involve two writes:
|
|
|
2733a1 |
the reflink of the full size, then a fork/copy on write for the last
|
|
|
2733a1 |
page worth.
|
|
|
2733a1 |
|
|
|
2733a1 |
If the file passed to `reflink_fsm_file_pre()` is anything other than a
|
|
|
2733a1 |
regular file, it return `RPMRC_OK` so the normal mechanics of
|
|
|
2733a1 |
`rpmPackageFilesInstall()` are used. That handles directories, symlinks
|
|
|
2733a1 |
and other non file types.
|
|
|
2733a1 |
|
|
|
2733a1 |
= New API for internal use
|
|
|
2733a1 |
|
|
|
2733a1 |
1. `rpmReadPackageRaw()` is used within `rpm2extents` to read all the
|
|
|
2733a1 |
headers without trying to validate signatures. This eliminates the
|
|
|
2733a1 |
runtime dependency on rpmdb.
|
|
|
2733a1 |
2. `rpmteFd()` exposes the Fd behind the rpmte, so plugins can interact
|
|
|
2733a1 |
with the rpm itself.
|
|
|
2733a1 |
3. `RPMRC_PLUGIN_CONTENTS` in `rpmRC_e` for use in
|
|
|
2733a1 |
`rpmpluginsCallFsmFilePre()` specifically.
|
|
|
2733a1 |
4. `pgpStringVal()` is used to help parse the command line in
|
|
|
2733a1 |
`rpm2extents` - the positional arguments are strings, and this
|
|
|
2733a1 |
converts the values back to the values in the table.
|
|
|
2733a1 |
|
|
|
2733a1 |
Nothing has been removed, and none of the changes are intended to be
|
|
|
2733a1 |
used externally, so I don't think a soname bump is warranted here.
|
|
|
2733a1 |
|
|
|
2733a1 |
Co-authored-by: Matthew Almond <malmond@meta.com>
|
|
|
2733a1 |
---
|
|
|
2733a1 |
build/pack.c | 2 +-
|
|
|
2733a1 |
include/rpm/rpmcli.h | 10 +
|
|
|
2733a1 |
include/rpm/rpmextents_internal.h | 58 +++
|
|
|
2733a1 |
include/rpm/rpmlib.h | 9 +
|
|
|
2733a1 |
include/rpm/rpmpgp.h | 9 +
|
|
|
2733a1 |
include/rpm/rpmte.h | 2 +
|
|
|
2733a1 |
include/rpm/rpmtypes.h | 3 +-
|
|
|
2733a1 |
lib/CMakeLists.txt | 1 +
|
|
|
2733a1 |
lib/fsm.c | 45 +-
|
|
|
2733a1 |
lib/package.c | 36 ++
|
|
|
2733a1 |
lib/rpmchecksig.c | 116 ++++-
|
|
|
2733a1 |
lib/rpmextents.c | 109 +++++
|
|
|
2733a1 |
lib/rpmlead.c | 43 +-
|
|
|
2733a1 |
lib/rpmlead.h | 37 +-
|
|
|
2733a1 |
lib/rpmplugin.h | 9 +
|
|
|
2733a1 |
lib/rpmplugins.c | 94 +++-
|
|
|
2733a1 |
lib/rpmplugins.h | 17 +
|
|
|
2733a1 |
lib/rpmte.c | 5 +
|
|
|
2733a1 |
lib/transaction.c | 29 +-
|
|
|
2733a1 |
macros.in | 1 +
|
|
|
2733a1 |
plugins/CMakeLists.txt | 4 +-
|
|
|
2733a1 |
plugins/reflink.c | 401 +++++++++++++++++
|
|
|
2733a1 |
rpmio/rpmpgp.c | 28 ++
|
|
|
2733a1 |
rpmio/rpmpgp_internal.c | 18 -
|
|
|
2733a1 |
scripts/CMakeLists.txt | 2 +-
|
|
|
2733a1 |
scripts/rpm2extents_dump | 94 ++++
|
|
|
2733a1 |
tests/CMakeLists.txt | 1 +
|
|
|
2733a1 |
tests/atlocal.in | 21 +
|
|
|
2733a1 |
tests/rpm2extents.at | 151 +++++++
|
|
|
2733a1 |
tests/rpmtests.at | 1 +
|
|
|
2733a1 |
tools/CMakeLists.txt | 5 +-
|
|
|
2733a1 |
tools/rpm2extents.c | 707 ++++++++++++++++++++++++++++++
|
|
|
2733a1 |
32 files changed, 1978 insertions(+), 90 deletions(-)
|
|
|
2733a1 |
create mode 100644 include/rpm/rpmextents_internal.h
|
|
|
2733a1 |
create mode 100644 lib/rpmextents.c
|
|
|
2733a1 |
create mode 100644 plugins/reflink.c
|
|
|
2733a1 |
create mode 100755 scripts/rpm2extents_dump
|
|
|
2733a1 |
create mode 100644 tests/rpm2extents.at
|
|
|
2733a1 |
create mode 100644 tools/rpm2extents.c
|
|
|
2733a1 |
|
|
|
2733a1 |
diff --git a/build/pack.c b/build/pack.c
|
|
|
2733a1 |
index f7dac6d..c38b1a9 100644
|
|
|
2733a1 |
--- a/build/pack.c
|
|
|
2733a1 |
+++ b/build/pack.c
|
|
|
2733a1 |
@@ -495,7 +495,7 @@ static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp,
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
/* Write the lead section into the package. */
|
|
|
2733a1 |
- if (rpmLeadWrite(fd, pkg->header)) {
|
|
|
2733a1 |
+ if (rpmLeadWriteFromHeader(fd, pkg->header)) {
|
|
|
2733a1 |
rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd));
|
|
|
2733a1 |
goto exit;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
diff --git a/include/rpm/rpmcli.h b/include/rpm/rpmcli.h
|
|
|
2733a1 |
index 3e5900d..09274e3 100644
|
|
|
2733a1 |
--- a/include/rpm/rpmcli.h
|
|
|
2733a1 |
+++ b/include/rpm/rpmcli.h
|
|
|
2733a1 |
@@ -421,6 +421,16 @@ int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv);
|
|
|
2733a1 |
*/
|
|
|
2733a1 |
int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv);
|
|
|
2733a1 |
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/** \ingroup rpmcli
|
|
|
2733a1 |
+ * Verify package signatures.
|
|
|
2733a1 |
+ * @param ts transaction set
|
|
|
2733a1 |
+ * @param fd a file descriptor to verify
|
|
|
2733a1 |
+ * @param msg a string containing textual information about the verification, similar to rpmcliVerifySignatures output.
|
|
|
2733a1 |
+ * @return 0 on success
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd, char **msg);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
#ifdef __cplusplus
|
|
|
2733a1 |
}
|
|
|
2733a1 |
#endif
|
|
|
2733a1 |
diff --git a/include/rpm/rpmextents_internal.h b/include/rpm/rpmextents_internal.h
|
|
|
2733a1 |
new file mode 100644
|
|
|
2733a1 |
index 0000000..0a3318c
|
|
|
2733a1 |
--- /dev/null
|
|
|
2733a1 |
+++ b/include/rpm/rpmextents_internal.h
|
|
|
2733a1 |
@@ -0,0 +1,58 @@
|
|
|
2733a1 |
+#ifndef _RPMEXTENTS_INTERNAL_H
|
|
|
2733a1 |
+#define _RPMEXTENTS_INTERNAL_H
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#ifdef __cplusplus
|
|
|
2733a1 |
+extern "C" {
|
|
|
2733a1 |
+#endif
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include <stdint.h>
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/** \ingroup rpmextents
|
|
|
2733a1 |
+ * RPM extents library
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/* magic value at end of file (64 bits) that indicates this is a transcoded
|
|
|
2733a1 |
+ * rpm.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+#define EXTENTS_MAGIC 3472329499408095051
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+typedef uint64_t extents_magic_t;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+struct __attribute__ ((__packed__)) extents_footer_offsets_t {
|
|
|
2733a1 |
+ off64_t checksig_offset;
|
|
|
2733a1 |
+ off64_t table_offset;
|
|
|
2733a1 |
+ off64_t csum_offset;
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+struct __attribute__ ((__packed__)) extents_footer_t {
|
|
|
2733a1 |
+ struct extents_footer_offsets_t offsets;
|
|
|
2733a1 |
+ extents_magic_t magic;
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/** \ingroup rpmextents
|
|
|
2733a1 |
+ * Checks the results of the signature verification ran during transcoding.
|
|
|
2733a1 |
+ * @param fd The FD_t of the transcoded RPM
|
|
|
2733a1 |
+ * @param print_content Whether or not to print the result from rpmsig
|
|
|
2733a1 |
+ * @return The number of checks that `rpmvsVerify` failed during transcoding.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+int extentsVerifySigs(FD_t fd, int print_content);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/** \ingroup rpmextents
|
|
|
2733a1 |
+ * Read the RPM Extents footer from a file descriptor.
|
|
|
2733a1 |
+ * @param fd The FD_t of the transcoded RPM
|
|
|
2733a1 |
+ * @param[out] footer A pointer to an allocated extents_footer_t with a copy of the footer.
|
|
|
2733a1 |
+ * @return RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/** \ingroup rpmextents
|
|
|
2733a1 |
+ * Check if a RPM is a transcoded RPM
|
|
|
2733a1 |
+ * @param fd The FD_t of the transcoded RPM
|
|
|
2733a1 |
+ * return RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+rpmRC isTranscodedRpm(FD_t fd);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#ifdef __cplusplus
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+#endif
|
|
|
2733a1 |
+#endif /* _RPMEXTENTS_INTERNAL_H */
|
|
|
2733a1 |
diff --git a/include/rpm/rpmlib.h b/include/rpm/rpmlib.h
|
|
|
2733a1 |
index db38397..b11f87f 100644
|
|
|
2733a1 |
--- a/include/rpm/rpmlib.h
|
|
|
2733a1 |
+++ b/include/rpm/rpmlib.h
|
|
|
2733a1 |
@@ -155,6 +155,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg);
|
|
|
2733a1 |
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd,
|
|
|
2733a1 |
const char * fn, Header * hdrp);
|
|
|
2733a1 |
|
|
|
2733a1 |
+/** \ingroup header
|
|
|
2733a1 |
+ * Return package signature, header from file handle, no verification.
|
|
|
2733a1 |
+ * @param fd file handle
|
|
|
2733a1 |
+ * @param[out] sigp address of header (or NULL)
|
|
|
2733a1 |
+ * @param[out] hdrp address of header (or NULL)
|
|
|
2733a1 |
+ * @return RPMRC_OK on success
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
/** \ingroup rpmtrans
|
|
|
2733a1 |
* Install source package.
|
|
|
2733a1 |
* @param ts transaction set
|
|
|
2733a1 |
diff --git a/include/rpm/rpmpgp.h b/include/rpm/rpmpgp.h
|
|
|
2733a1 |
index a7eecbe..24e9617 100644
|
|
|
2733a1 |
--- a/include/rpm/rpmpgp.h
|
|
|
2733a1 |
+++ b/include/rpm/rpmpgp.h
|
|
|
2733a1 |
@@ -962,6 +962,15 @@ typedef enum pgpValType_e {
|
|
|
2733a1 |
*/
|
|
|
2733a1 |
const char * pgpValString(pgpValType type, uint8_t val);
|
|
|
2733a1 |
|
|
|
2733a1 |
+/** \ingroup rpmpgp
|
|
|
2733a1 |
+ * Return OpenPGP value for a string.
|
|
|
2733a1 |
+ * @param type type of value
|
|
|
2733a1 |
+ * @param str string to lookup
|
|
|
2733a1 |
+ * @param[out] val byte value associated with string
|
|
|
2733a1 |
+ * @return 0 on success else -1
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+int pgpStringVal(pgpValType type, const char *str, uint8_t *val);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
/** \ingroup rpmpgp
|
|
|
2733a1 |
* Return (native-endian) integer from big-endian representation.
|
|
|
2733a1 |
* @param s pointer to big-endian integer
|
|
|
2733a1 |
diff --git a/include/rpm/rpmte.h b/include/rpm/rpmte.h
|
|
|
2733a1 |
index effcdab..499fd4f 100644
|
|
|
2733a1 |
--- a/include/rpm/rpmte.h
|
|
|
2733a1 |
+++ b/include/rpm/rpmte.h
|
|
|
2733a1 |
@@ -209,6 +209,8 @@ const char * rpmteNEVR(rpmte te);
|
|
|
2733a1 |
*/
|
|
|
2733a1 |
const char * rpmteNEVRA(rpmte te);
|
|
|
2733a1 |
|
|
|
2733a1 |
+FD_t rpmteFd(rpmte te);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
/** \ingroup rpmte
|
|
|
2733a1 |
* Retrieve key from transaction element.
|
|
|
2733a1 |
* @param te transaction element
|
|
|
2733a1 |
diff --git a/include/rpm/rpmtypes.h b/include/rpm/rpmtypes.h
|
|
|
2733a1 |
index 7c14553..552ec52 100644
|
|
|
2733a1 |
--- a/include/rpm/rpmtypes.h
|
|
|
2733a1 |
+++ b/include/rpm/rpmtypes.h
|
|
|
2733a1 |
@@ -106,7 +106,8 @@ typedef enum rpmRC_e {
|
|
|
2733a1 |
RPMRC_NOTFOUND = 1, /*!< Generic not found code. */
|
|
|
2733a1 |
RPMRC_FAIL = 2, /*!< Generic failure code. */
|
|
|
2733a1 |
RPMRC_NOTTRUSTED = 3, /*!< Signature is OK, but key is not trusted. */
|
|
|
2733a1 |
- RPMRC_NOKEY = 4 /*!< Public key is unavailable. */
|
|
|
2733a1 |
+ RPMRC_NOKEY = 4, /*!< Public key is unavailable. */
|
|
|
2733a1 |
+ RPMRC_PLUGIN_CONTENTS = 5 /*!< fsm_file_pre plugin is handling content */
|
|
|
2733a1 |
} rpmRC;
|
|
|
2733a1 |
|
|
|
2733a1 |
#ifdef __cplusplus
|
|
|
2733a1 |
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
|
|
|
2733a1 |
index 2528a64..754a198 100644
|
|
|
2733a1 |
--- a/lib/CMakeLists.txt
|
|
|
2733a1 |
+++ b/lib/CMakeLists.txt
|
|
|
2733a1 |
@@ -41,6 +41,7 @@ target_sources(librpm PRIVATE
|
|
|
2733a1 |
rpmchroot.c rpmchroot.h
|
|
|
2733a1 |
rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h
|
|
|
2733a1 |
rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h
|
|
|
2733a1 |
+ rpmextents.c
|
|
|
2733a1 |
)
|
|
|
2733a1 |
|
|
|
2733a1 |
if(ENABLE_SQLITE)
|
|
|
2733a1 |
diff --git a/lib/fsm.c b/lib/fsm.c
|
|
|
2733a1 |
index 36708ac..2df7db7 100644
|
|
|
2733a1 |
--- a/lib/fsm.c
|
|
|
2733a1 |
+++ b/lib/fsm.c
|
|
|
2733a1 |
@@ -869,6 +869,24 @@ static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di)
|
|
|
2733a1 |
return rpmfiFree(fi);
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
+static int fiIterator(rpmPlugins plugins, FD_t payload, rpmfiles files, rpmfi *fi)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ rpmRC plugin_rc = rpmpluginsCallFsmFileArchiveReader(plugins, payload, files, fi);
|
|
|
2733a1 |
+ switch (plugin_rc) {
|
|
|
2733a1 |
+ case RPMRC_PLUGIN_CONTENTS:
|
|
|
2733a1 |
+ if (*fi == NULL)
|
|
|
2733a1 |
+ return RPMERR_BAD_MAGIC;
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+ case RPMRC_OK:
|
|
|
2733a1 |
+ *fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
|
|
|
2733a1 |
+ if (*fi == NULL)
|
|
|
2733a1 |
+ return RPMERR_BAD_MAGIC;
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+ default:
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
2733a1 |
rpmpsm psm, char ** failedFile)
|
|
|
2733a1 |
{
|
|
|
2733a1 |
@@ -920,8 +938,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
2733a1 |
if (rc)
|
|
|
2733a1 |
goto exit;
|
|
|
2733a1 |
|
|
|
2733a1 |
- fi = fsmIter(payload, files,
|
|
|
2733a1 |
- payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di);
|
|
|
2733a1 |
+ rc = fiIterator(plugins, payload, files, &fi);
|
|
|
2733a1 |
+ if (rc)
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
|
|
|
2733a1 |
if (fi == NULL) {
|
|
|
2733a1 |
rc = RPMERR_BAD_MAGIC;
|
|
|
2733a1 |
@@ -944,6 +963,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
2733a1 |
if (!fp->skip) {
|
|
|
2733a1 |
int mayopen = 0;
|
|
|
2733a1 |
int fd = -1;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (di.dirfd >= 0)
|
|
|
2733a1 |
+ fsmClose(&di.dirfd);
|
|
|
2733a1 |
rc = ensureDir(plugins, rpmfiDN(fi), 0,
|
|
|
2733a1 |
(fp->action == FA_CREATE), 0, &di.dirfd);
|
|
|
2733a1 |
|
|
|
2733a1 |
@@ -953,9 +975,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
/* Run fsm file pre hook for all plugins */
|
|
|
2733a1 |
- if (!rc)
|
|
|
2733a1 |
+ if (!rc) {
|
|
|
2733a1 |
rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
|
|
|
2733a1 |
fp->sb.st_mode, fp->action);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
if (rc)
|
|
|
2733a1 |
goto setmeta; /* for error notification */
|
|
|
2733a1 |
|
|
|
2733a1 |
@@ -983,11 +1006,18 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
2733a1 |
if (fp->action == FA_TOUCH)
|
|
|
2733a1 |
goto setmeta;
|
|
|
2733a1 |
|
|
|
2733a1 |
- if (S_ISREG(fp->sb.st_mode)) {
|
|
|
2733a1 |
+ rpmRC plugin_rc = rpmpluginsCallFsmFileInstall(plugins, fi, fp->fpath, fp->sb.st_mode, fp->action);
|
|
|
2733a1 |
+ if (!(plugin_rc == RPMRC_PLUGIN_CONTENTS || plugin_rc == RPMRC_OK)){
|
|
|
2733a1 |
+ rc = plugin_rc;
|
|
|
2733a1 |
+ } else if(plugin_rc == RPMRC_PLUGIN_CONTENTS){
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+ /* The reflink plugins handles hardlink differently, metadata has to be set. */
|
|
|
2733a1 |
+ fp->setmeta = 1;
|
|
|
2733a1 |
+ } else if (S_ISREG(fp->sb.st_mode)) {
|
|
|
2733a1 |
if (rc == RPMERR_ENOENT) {
|
|
|
2733a1 |
rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
|
|
|
2733a1 |
- &firstlink, &firstlinkfile, &di.firstdir,
|
|
|
2733a1 |
- &fd;;
|
|
|
2733a1 |
+ &firstlink, &firstlinkfile,
|
|
|
2733a1 |
+ &di.firstdir, &fd;;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
} else if (S_ISDIR(fp->sb.st_mode)) {
|
|
|
2733a1 |
if (rc == RPMERR_ENOENT) {
|
|
|
2733a1 |
@@ -1056,10 +1086,13 @@ setmeta:
|
|
|
2733a1 |
|
|
|
2733a1 |
/* If all went well, commit files to final destination */
|
|
|
2733a1 |
fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
while (!rc && (fx = rpmfiNext(fi)) >= 0) {
|
|
|
2733a1 |
struct filedata_s *fp = &fdata[fx];
|
|
|
2733a1 |
|
|
|
2733a1 |
if (!fp->skip) {
|
|
|
2733a1 |
+ if (di.dirfd >= 0)
|
|
|
2733a1 |
+ fsmClose(&di.dirfd);
|
|
|
2733a1 |
if (!rc)
|
|
|
2733a1 |
rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd);
|
|
|
2733a1 |
|
|
|
2733a1 |
diff --git a/lib/package.c b/lib/package.c
|
|
|
2733a1 |
index 8eee368..d4256a7 100644
|
|
|
2733a1 |
--- a/lib/package.c
|
|
|
2733a1 |
+++ b/lib/package.c
|
|
|
2733a1 |
@@ -394,5 +394,41 @@ exit:
|
|
|
2733a1 |
return rc;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
+rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ char *msg = NULL;
|
|
|
2733a1 |
+ hdrblob sigblob = hdrblobCreate();
|
|
|
2733a1 |
+ hdrblob blob = hdrblobCreate();
|
|
|
2733a1 |
+ Header h = NULL;
|
|
|
2733a1 |
+ Header sigh = NULL;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rpmRC rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg;;
|
|
|
2733a1 |
+ if (rc != RPMRC_OK)
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rc = hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, blob, &msg;;
|
|
|
2733a1 |
+ if (rc != RPMRC_OK)
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rc = hdrblobImport(sigblob, 0, &sigh, &msg;;
|
|
|
2733a1 |
+ if (rc)
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rc = hdrblobImport(blob, 0, &h, &msg;;
|
|
|
2733a1 |
+ if (rc)
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ *sigp = headerLink(sigh);
|
|
|
2733a1 |
+ *hdrp = headerLink(h);
|
|
|
2733a1 |
|
|
|
2733a1 |
+exit:
|
|
|
2733a1 |
+ if (rc != RPMRC_OK && msg)
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg);
|
|
|
2733a1 |
+ hdrblobFree(sigblob);
|
|
|
2733a1 |
+ hdrblobFree(blob);
|
|
|
2733a1 |
+ headerFree(sigh);
|
|
|
2733a1 |
+ headerFree(h);
|
|
|
2733a1 |
+ free(msg);
|
|
|
2733a1 |
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c
|
|
|
2733a1 |
index 3a3a4bd..8257dd9 100644
|
|
|
2733a1 |
--- a/lib/rpmchecksig.c
|
|
|
2733a1 |
+++ b/lib/rpmchecksig.c
|
|
|
2733a1 |
@@ -16,6 +16,7 @@
|
|
|
2733a1 |
#include <rpm/rpmlog.h>
|
|
|
2733a1 |
#include <rpm/rpmstring.h>
|
|
|
2733a1 |
#include <rpm/rpmkeyring.h>
|
|
|
2733a1 |
+#include <rpm/rpmextents_internal.h>
|
|
|
2733a1 |
|
|
|
2733a1 |
#include "rpmio_internal.h" /* fdSetBundle() */
|
|
|
2733a1 |
#include "rpmlead.h"
|
|
|
2733a1 |
@@ -208,36 +209,24 @@ exit:
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags,
|
|
|
2733a1 |
- FD_t fd, const char *fn)
|
|
|
2733a1 |
+ FD_t fd, rpmsinfoCb cb, void *cbdata)
|
|
|
2733a1 |
{
|
|
|
2733a1 |
char *msg = NULL;
|
|
|
2733a1 |
- struct vfydata_s vd = { .seen = 0,
|
|
|
2733a1 |
- .bad = 0,
|
|
|
2733a1 |
- .verbose = rpmIsVerbose(),
|
|
|
2733a1 |
- };
|
|
|
2733a1 |
int rc;
|
|
|
2733a1 |
- struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);
|
|
|
2733a1 |
|
|
|
2733a1 |
- rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : "");
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if(isTranscodedRpm(fd) == RPMRC_OK){
|
|
|
2733a1 |
+ return extentsVerifySigs(fd, 1);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring);
|
|
|
2733a1 |
|
|
|
2733a1 |
rc = rpmpkgRead(vs, fd, NULL, NULL, &msg;;
|
|
|
2733a1 |
|
|
|
2733a1 |
if (rc)
|
|
|
2733a1 |
goto exit;
|
|
|
2733a1 |
|
|
|
2733a1 |
- rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);
|
|
|
2733a1 |
-
|
|
|
2733a1 |
- if (!vd.verbose) {
|
|
|
2733a1 |
- if (vd.seen & RPMSIG_DIGEST_TYPE) {
|
|
|
2733a1 |
- rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_DIGEST_TYPE) ?
|
|
|
2733a1 |
- _("DIGESTS") : _("digests"));
|
|
|
2733a1 |
- }
|
|
|
2733a1 |
- if (vd.seen & RPMSIG_SIGNATURE_TYPE) {
|
|
|
2733a1 |
- rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ?
|
|
|
2733a1 |
- _("SIGNATURES") : _("signatures"));
|
|
|
2733a1 |
- }
|
|
|
2733a1 |
- rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));
|
|
|
2733a1 |
- }
|
|
|
2733a1 |
+ rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata);
|
|
|
2733a1 |
|
|
|
2733a1 |
exit:
|
|
|
2733a1 |
if (rc && msg)
|
|
|
2733a1 |
@@ -247,15 +236,39 @@ exit:
|
|
|
2733a1 |
return rc;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
+static void rpmkgVerifySigsPreLogging(struct vfydata_s *vd, const char *fn){
|
|
|
2733a1 |
+ rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd->verbose ? "\n" : "");
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static void rpmkgVerifySigsPostLogging(struct vfydata_s *vd, int rc){
|
|
|
2733a1 |
+ if (!vd->verbose) {
|
|
|
2733a1 |
+ if (vd->seen & RPMSIG_DIGEST_TYPE) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_DIGEST_TYPE) ?
|
|
|
2733a1 |
+ _("DIGESTS") : _("digests"));
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (vd->seen & RPMSIG_SIGNATURE_TYPE) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_SIGNATURE_TYPE) ?
|
|
|
2733a1 |
+ _("SIGNATURES") : _("signatures"));
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK"));
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
/* Wrapper around rpmkVerifySigs to preserve API */
|
|
|
2733a1 |
int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn)
|
|
|
2733a1 |
{
|
|
|
2733a1 |
int rc = 1; /* assume failure */
|
|
|
2733a1 |
+ struct vfydata_s vd = { .seen = 0,
|
|
|
2733a1 |
+ .bad = 0,
|
|
|
2733a1 |
+ .verbose = rpmIsVerbose(),
|
|
|
2733a1 |
+ };
|
|
|
2733a1 |
if (ts && qva && fd && fn) {
|
|
|
2733a1 |
rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
|
|
|
2733a1 |
rpmVSFlags vsflags = rpmtsVfyFlags(ts);
|
|
|
2733a1 |
int vfylevel = rpmtsVfyLevel(ts);
|
|
|
2733a1 |
- rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, fn);
|
|
|
2733a1 |
+ rpmkgVerifySigsPreLogging(&vd, fn);
|
|
|
2733a1 |
+ rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, vfyCb, &vd);
|
|
|
2733a1 |
+ rpmkgVerifySigsPostLogging(&vd, rc);
|
|
|
2733a1 |
rpmKeyringFree(keyring);
|
|
|
2733a1 |
}
|
|
|
2733a1 |
return rc;
|
|
|
2733a1 |
@@ -277,12 +290,22 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
|
|
|
2733a1 |
|
|
|
2733a1 |
while ((arg = *argv++) != NULL) {
|
|
|
2733a1 |
FD_t fd = Fopen(arg, "r.ufdio");
|
|
|
2733a1 |
+ struct vfydata_s vd = { .seen = 0,
|
|
|
2733a1 |
+ .bad = 0,
|
|
|
2733a1 |
+ .verbose = rpmIsVerbose(),
|
|
|
2733a1 |
+ };
|
|
|
2733a1 |
if (fd == NULL || Ferror(fd)) {
|
|
|
2733a1 |
rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
|
|
|
2733a1 |
arg, Fstrerror(fd));
|
|
|
2733a1 |
res++;
|
|
|
2733a1 |
- } else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, arg)) {
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ rpmkgVerifySigsPreLogging(&vd, arg);
|
|
|
2733a1 |
+ int rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd,
|
|
|
2733a1 |
+ vfyCb, &vd);
|
|
|
2733a1 |
+ rpmkgVerifySigsPostLogging(&vd, rc);
|
|
|
2733a1 |
+ if (rc) {
|
|
|
2733a1 |
res++;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
Fclose(fd);
|
|
|
2733a1 |
@@ -290,3 +313,52 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv)
|
|
|
2733a1 |
rpmKeyringFree(keyring);
|
|
|
2733a1 |
return res;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+struct vfydatafd_s {
|
|
|
2733a1 |
+ size_t len;
|
|
|
2733a1 |
+ char msg[BUFSIZ];
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static int vfyFDCb(struct rpmsinfo_s *sinfo, void *cbdata)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ struct vfydatafd_s *vd = cbdata;
|
|
|
2733a1 |
+ char *vmsg, *msg;
|
|
|
2733a1 |
+ size_t n;
|
|
|
2733a1 |
+ size_t remainder = BUFSIZ - vd->len >= 0 ? BUFSIZ - vd->len : 0;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ vmsg = rpmsinfoMsg(sinfo);
|
|
|
2733a1 |
+ rasprintf(&msg, " %s\n", vmsg);
|
|
|
2733a1 |
+ n = rstrlcpy(vd->msg + vd->len, msg, remainder);
|
|
|
2733a1 |
+ free(vmsg);
|
|
|
2733a1 |
+ free(msg);
|
|
|
2733a1 |
+ if(n <= remainder){
|
|
|
2733a1 |
+ vd->len += n;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return 1;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi, char **msg)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
|
|
|
2733a1 |
+ rpmVSFlags vsflags = rpmtsVfyFlags(ts);
|
|
|
2733a1 |
+ int vfylevel = rpmtsVfyLevel(ts);
|
|
|
2733a1 |
+ struct vfydatafd_s vd = {.len = 0};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ vsflags |= rpmcliVSFlags;
|
|
|
2733a1 |
+ if (rpmcliVfyLevelMask) {
|
|
|
2733a1 |
+ vfylevel &= ~rpmcliVfyLevelMask;
|
|
|
2733a1 |
+ rpmtsSetVfyLevel(ts, vfylevel);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (!rpmpkgVerifySigs(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) {
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ *msg = strdup(vd.msg);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rpmKeyringFree(keyring);
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
diff --git a/lib/rpmextents.c b/lib/rpmextents.c
|
|
|
2733a1 |
new file mode 100644
|
|
|
2733a1 |
index 0000000..ef687d6
|
|
|
2733a1 |
--- /dev/null
|
|
|
2733a1 |
+++ b/lib/rpmextents.c
|
|
|
2733a1 |
@@ -0,0 +1,109 @@
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include "system.h"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include <rpm/rpmlog.h>
|
|
|
2733a1 |
+#include <rpm/rpmio.h>
|
|
|
2733a1 |
+#include <rpm/rpmextents_internal.h>
|
|
|
2733a1 |
+#include <string.h>
|
|
|
2733a1 |
+#include <errno.h>
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+int extentsVerifySigs(FD_t fd, int print_content){
|
|
|
2733a1 |
+ rpm_loff_t current;
|
|
|
2733a1 |
+ int32_t rc;
|
|
|
2733a1 |
+ size_t len;
|
|
|
2733a1 |
+ uint64_t content_len;
|
|
|
2733a1 |
+ char *content = NULL;
|
|
|
2733a1 |
+ struct extents_footer_t footer;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ current = Ftell(fd);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) {
|
|
|
2733a1 |
+ rc = -1;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to seek signature verification offset\n"));
|
|
|
2733a1 |
+ rc = -1;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ len = sizeof(rc);
|
|
|
2733a1 |
+ if (Fread(&rc, len, 1, fd) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read Signature Verification RC\n"));
|
|
|
2733a1 |
+ rc = -1;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if(print_content) {
|
|
|
2733a1 |
+ len = sizeof(content_len);
|
|
|
2733a1 |
+ if (Fread(&content_len, len, 1, fd) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n"));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ content = rmalloc(content_len + 1);
|
|
|
2733a1 |
+ if(content == NULL) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n"));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ content[content_len] = 0;
|
|
|
2733a1 |
+ if (Fread(content, content_len, 1, fd) != content_len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n"));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rpmlog(RPMLOG_NOTICE, "%s", content);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+exit:
|
|
|
2733a1 |
+ if(content){
|
|
|
2733a1 |
+ rfree(content);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (Fseek(fd, current, SEEK_SET) < 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: unable to seek back to original location\n"));
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) {
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_NOTFOUND;
|
|
|
2733a1 |
+ rpm_loff_t current;
|
|
|
2733a1 |
+ size_t len;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ // If the file is not seekable, we cannot detect whether or not it is transcoded.
|
|
|
2733a1 |
+ if(Fseek(fd, 0, SEEK_CUR) < 0) {
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ current = Ftell(fd);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ len = sizeof(struct extents_footer_t);
|
|
|
2733a1 |
+ if(Fseek(fd, -len, SEEK_END) < 0) {
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (Fread(footer, len, 1, fd) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read footer\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (footer->magic != EXTENTS_MAGIC) {
|
|
|
2733a1 |
+ rc = RPMRC_NOTFOUND;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+exit:
|
|
|
2733a1 |
+ if (Fseek(fd, current, SEEK_SET) < 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpmRC isTranscodedRpm(FD_t fd) {
|
|
|
2733a1 |
+ struct extents_footer_t footer;
|
|
|
2733a1 |
+ return extentsFooterFromFD(fd, &footer);
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
diff --git a/lib/rpmlead.c b/lib/rpmlead.c
|
|
|
2733a1 |
index d0db60a..e4504d2 100644
|
|
|
2733a1 |
--- a/lib/rpmlead.c
|
|
|
2733a1 |
+++ b/lib/rpmlead.c
|
|
|
2733a1 |
@@ -24,24 +24,6 @@ static unsigned char const lead_magic[] = {
|
|
|
2733a1 |
RPMLEAD_MAGIC0, RPMLEAD_MAGIC1, RPMLEAD_MAGIC2, RPMLEAD_MAGIC3
|
|
|
2733a1 |
};
|
|
|
2733a1 |
|
|
|
2733a1 |
-/** \ingroup lead
|
|
|
2733a1 |
- * The lead data structure.
|
|
|
2733a1 |
- * The lead needs to be 8 byte aligned.
|
|
|
2733a1 |
- * @deprecated The lead (except for signature_type) is legacy.
|
|
|
2733a1 |
- * @todo Don't use any information from lead.
|
|
|
2733a1 |
- */
|
|
|
2733a1 |
-struct rpmlead_s {
|
|
|
2733a1 |
- unsigned char magic[4];
|
|
|
2733a1 |
- unsigned char major;
|
|
|
2733a1 |
- unsigned char minor;
|
|
|
2733a1 |
- short type;
|
|
|
2733a1 |
- short archnum;
|
|
|
2733a1 |
- char name[66];
|
|
|
2733a1 |
- short osnum;
|
|
|
2733a1 |
- short signature_type; /*!< Signature header type (RPMSIG_HEADERSIG) */
|
|
|
2733a1 |
- char reserved[16]; /*!< Pad to 96 bytes -- 8 byte aligned! */
|
|
|
2733a1 |
-};
|
|
|
2733a1 |
-
|
|
|
2733a1 |
static int rpmLeadFromHeader(Header h, struct rpmlead_s *l)
|
|
|
2733a1 |
{
|
|
|
2733a1 |
if (h != NULL) {
|
|
|
2733a1 |
@@ -70,13 +52,23 @@ static int rpmLeadFromHeader(Header h, struct rpmlead_s *l)
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
/* The lead needs to be 8 byte aligned */
|
|
|
2733a1 |
-rpmRC rpmLeadWrite(FD_t fd, Header h)
|
|
|
2733a1 |
+rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h)
|
|
|
2733a1 |
{
|
|
|
2733a1 |
rpmRC rc = RPMRC_FAIL;
|
|
|
2733a1 |
struct rpmlead_s l;
|
|
|
2733a1 |
|
|
|
2733a1 |
- if (rpmLeadFromHeader(h, &l)) {
|
|
|
2733a1 |
-
|
|
|
2733a1 |
+ if (rpmLeadFromHeader(h, &l)) {
|
|
|
2733a1 |
+ rc = rpmLeadWrite(fd, l);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/* The lead needs to be 8 byte aligned */
|
|
|
2733a1 |
+rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_FAIL;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
l.type = htons(l.type);
|
|
|
2733a1 |
l.archnum = htons(l.archnum);
|
|
|
2733a1 |
l.osnum = htons(l.osnum);
|
|
|
2733a1 |
@@ -84,7 +76,6 @@ rpmRC rpmLeadWrite(FD_t fd, Header h)
|
|
|
2733a1 |
|
|
|
2733a1 |
if (Fwrite(&l, 1, sizeof(l), fd) == sizeof(l))
|
|
|
2733a1 |
rc = RPMRC_OK;
|
|
|
2733a1 |
- }
|
|
|
2733a1 |
|
|
|
2733a1 |
return rc;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
@@ -99,6 +90,11 @@ static rpmRC rpmLeadCheck(struct rpmlead_s *lead, char **msg)
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
rpmRC rpmLeadRead(FD_t fd, char **emsg)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ return rpmLeadReadAndReturn(fd, emsg, NULL);
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret)
|
|
|
2733a1 |
{
|
|
|
2733a1 |
rpmRC rc = RPMRC_OK;
|
|
|
2733a1 |
struct rpmlead_s l;
|
|
|
2733a1 |
@@ -128,5 +124,8 @@ rpmRC rpmLeadRead(FD_t fd, char **emsg)
|
|
|
2733a1 |
free(err);
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
+ if (ret)
|
|
|
2733a1 |
+ *ret = l;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
return rc;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
diff --git a/lib/rpmlead.h b/lib/rpmlead.h
|
|
|
2733a1 |
index 80db44e..4ba2ba9 100644
|
|
|
2733a1 |
--- a/lib/rpmlead.h
|
|
|
2733a1 |
+++ b/lib/rpmlead.h
|
|
|
2733a1 |
@@ -19,13 +19,39 @@ extern "C" {
|
|
|
2733a1 |
|
|
|
2733a1 |
#define RPMLEAD_SIZE 96 /*!< Don't rely on sizeof(struct) */
|
|
|
2733a1 |
|
|
|
2733a1 |
+/** \ingroup lead
|
|
|
2733a1 |
+ * The lead data structure.
|
|
|
2733a1 |
+ * The lead needs to be 8 byte aligned.
|
|
|
2733a1 |
+ * @deprecated The lead (except for signature_type) is legacy.
|
|
|
2733a1 |
+ * @todo Don't use any information from lead.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+struct rpmlead_s {
|
|
|
2733a1 |
+ unsigned char magic[4];
|
|
|
2733a1 |
+ unsigned char major;
|
|
|
2733a1 |
+ unsigned char minor;
|
|
|
2733a1 |
+ short type;
|
|
|
2733a1 |
+ short archnum;
|
|
|
2733a1 |
+ char name[66];
|
|
|
2733a1 |
+ short osnum;
|
|
|
2733a1 |
+ short signature_type; /*!< Signature header type (RPMSIG_HEADERSIG) */
|
|
|
2733a1 |
+ char reserved[16]; /*!< Pad to 96 bytes -- 8 byte aligned! */
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
/** \ingroup lead
|
|
|
2733a1 |
* Write lead to file handle.
|
|
|
2733a1 |
* @param fd file handle
|
|
|
2733a1 |
* @param h package header
|
|
|
2733a1 |
* @return RPMRC_OK on success, RPMRC_FAIL on error
|
|
|
2733a1 |
*/
|
|
|
2733a1 |
-rpmRC rpmLeadWrite(FD_t fd, Header h);
|
|
|
2733a1 |
+rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/** \ingroup lead
|
|
|
2733a1 |
+ * Write lead to file handle.
|
|
|
2733a1 |
+ * @param fd file handle
|
|
|
2733a1 |
+ * @param l lead
|
|
|
2733a1 |
+ * @return RPMRC_OK on success, RPMRC_FAIL on error
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l);
|
|
|
2733a1 |
|
|
|
2733a1 |
/** \ingroup lead
|
|
|
2733a1 |
* Read lead from file handle.
|
|
|
2733a1 |
@@ -35,6 +61,15 @@ rpmRC rpmLeadWrite(FD_t fd, Header h);
|
|
|
2733a1 |
*/
|
|
|
2733a1 |
rpmRC rpmLeadRead(FD_t fd, char **emsg);
|
|
|
2733a1 |
|
|
|
2733a1 |
+/** \ingroup lead
|
|
|
2733a1 |
+ * Read lead from file handle and return it.
|
|
|
2733a1 |
+ * @param fd file handle
|
|
|
2733a1 |
+ * @param[out] emsg failure message on error (malloced)
|
|
|
2733a1 |
+ * @param[out] ret address of lead
|
|
|
2733a1 |
+ * @return RPMRC_OK on success, RPMRC_FAIL/RPMRC_NOTFOUND on error
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
#ifdef __cplusplus
|
|
|
2733a1 |
}
|
|
|
2733a1 |
#endif
|
|
|
2733a1 |
diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h
|
|
|
2733a1 |
index fab4b3e..c82d6be 100644
|
|
|
2733a1 |
--- a/lib/rpmplugin.h
|
|
|
2733a1 |
+++ b/lib/rpmplugin.h
|
|
|
2733a1 |
@@ -60,6 +60,13 @@ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,
|
|
|
2733a1 |
int fd, const char* path,
|
|
|
2733a1 |
const char *dest,
|
|
|
2733a1 |
mode_t file_mode, rpmFsmOp op);
|
|
|
2733a1 |
+typedef rpmRC (*plugin_fsm_file_install_func)(rpmPlugin plugin, rpmfi fi,
|
|
|
2733a1 |
+ const char* path,
|
|
|
2733a1 |
+ mode_t file_mode, rpmFsmOp op);
|
|
|
2733a1 |
+typedef rpmRC (*plugin_fsm_file_archive_reader_func)(rpmPlugin plugin,
|
|
|
2733a1 |
+ FD_t payload,
|
|
|
2733a1 |
+ rpmfiles files, rpmfi *fi);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
|
|
|
2733a1 |
typedef struct rpmPluginHooks_s * rpmPluginHooks;
|
|
|
2733a1 |
struct rpmPluginHooks_s {
|
|
|
2733a1 |
@@ -80,6 +87,8 @@ struct rpmPluginHooks_s {
|
|
|
2733a1 |
plugin_fsm_file_pre_func fsm_file_pre;
|
|
|
2733a1 |
plugin_fsm_file_post_func fsm_file_post;
|
|
|
2733a1 |
plugin_fsm_file_prepare_func fsm_file_prepare;
|
|
|
2733a1 |
+ plugin_fsm_file_install_func fsm_file_install;
|
|
|
2733a1 |
+ plugin_fsm_file_archive_reader_func fsm_file_archive_reader;
|
|
|
2733a1 |
};
|
|
|
2733a1 |
|
|
|
2733a1 |
#ifdef __cplusplus
|
|
|
2733a1 |
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
|
|
|
2733a1 |
index 62e806b..24abe96 100644
|
|
|
2733a1 |
--- a/lib/rpmplugins.c
|
|
|
2733a1 |
+++ b/lib/rpmplugins.c
|
|
|
2733a1 |
@@ -364,14 +364,29 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
|
|
|
2733a1 |
plugin_fsm_file_pre_func hookFunc;
|
|
|
2733a1 |
int i;
|
|
|
2733a1 |
rpmRC rc = RPMRC_OK;
|
|
|
2733a1 |
+ rpmRC hook_rc;
|
|
|
2733a1 |
char *apath = abspath(fi, path);
|
|
|
2733a1 |
|
|
|
2733a1 |
for (i = 0; i < plugins->count; i++) {
|
|
|
2733a1 |
rpmPlugin plugin = plugins->plugins[i];
|
|
|
2733a1 |
RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);
|
|
|
2733a1 |
- if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op) == RPMRC_FAIL) {
|
|
|
2733a1 |
- rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
|
|
|
2733a1 |
- rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ if (hookFunc) {
|
|
|
2733a1 |
+ hook_rc = hookFunc(plugin, fi, apath, file_mode, op);
|
|
|
2733a1 |
+ if (hook_rc == RPMRC_FAIL) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
|
|
|
2733a1 |
+ if (rc == RPMRC_PLUGIN_CONTENTS) {
|
|
|
2733a1 |
+ /* Another plugin already said it'd handle contents. It's
|
|
|
2733a1 |
+ * undefined how these would combine, so treat this as a
|
|
|
2733a1 |
+ * failure condition.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ /* Plugin will handle content */
|
|
|
2733a1 |
+ rc = RPMRC_PLUGIN_CONTENTS;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
}
|
|
|
2733a1 |
}
|
|
|
2733a1 |
free(apath);
|
|
|
2733a1 |
@@ -420,3 +435,76 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
|
|
|
2733a1 |
|
|
|
2733a1 |
return rc;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,
|
|
|
2733a1 |
+ const char *path, mode_t file_mode,
|
|
|
2733a1 |
+ rpmFsmOp op)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ plugin_fsm_file_install_func hookFunc;
|
|
|
2733a1 |
+ int i;
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_OK;
|
|
|
2733a1 |
+ rpmRC hook_rc;
|
|
|
2733a1 |
+ char *apath = abspath(fi, path);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ for (i = 0; i < plugins->count; i++) {
|
|
|
2733a1 |
+ rpmPlugin plugin = plugins->plugins[i];
|
|
|
2733a1 |
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_install);
|
|
|
2733a1 |
+ if (hookFunc) {
|
|
|
2733a1 |
+ hook_rc = hookFunc(plugin, fi, apath, file_mode, op);
|
|
|
2733a1 |
+ if (hook_rc == RPMRC_FAIL) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_install failed\n", plugin->name);
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
|
|
|
2733a1 |
+ if (rc == RPMRC_PLUGIN_CONTENTS) {
|
|
|
2733a1 |
+ /* Another plugin already said it'd handle contents. It's
|
|
|
2733a1 |
+ * undefined how these would combine, so treat this as a
|
|
|
2733a1 |
+ * failure condition.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ /* Plugin will handle content */
|
|
|
2733a1 |
+ rc = RPMRC_PLUGIN_CONTENTS;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ free(apath);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload,
|
|
|
2733a1 |
+ rpmfiles files, rpmfi *fi)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ plugin_fsm_file_archive_reader_func hookFunc;
|
|
|
2733a1 |
+ int i;
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_OK;
|
|
|
2733a1 |
+ rpmRC hook_rc;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ for (i = 0; i < plugins->count; i++) {
|
|
|
2733a1 |
+ rpmPlugin plugin = plugins->plugins[i];
|
|
|
2733a1 |
+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_archive_reader);
|
|
|
2733a1 |
+ if (hookFunc) {
|
|
|
2733a1 |
+ hook_rc = hookFunc(plugin, payload, files, fi);
|
|
|
2733a1 |
+ if (hook_rc == RPMRC_FAIL) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_archive_reader failed\n", plugin->name);
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
|
|
|
2733a1 |
+ if (rc == RPMRC_PLUGIN_CONTENTS) {
|
|
|
2733a1 |
+ /* Another plugin already said it'd handle contents. It's
|
|
|
2733a1 |
+ * undefined how these would combine, so treat this as a
|
|
|
2733a1 |
+ * failure condition.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ /* Plugin will handle content */
|
|
|
2733a1 |
+ rc = RPMRC_PLUGIN_CONTENTS;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
|
|
|
2733a1 |
index 287a302..a00f156 100644
|
|
|
2733a1 |
--- a/lib/rpmplugins.h
|
|
|
2733a1 |
+++ b/lib/rpmplugins.h
|
|
|
2733a1 |
@@ -168,6 +168,23 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
|
|
|
2733a1 |
int fd, const char *path, const char *dest,
|
|
|
2733a1 |
mode_t mode, rpmFsmOp op);
|
|
|
2733a1 |
|
|
|
2733a1 |
+/** \ingroup rpmplugins
|
|
|
2733a1 |
+ * Call the fsm file install plugin hook
|
|
|
2733a1 |
+ * @param plugins plugins structure
|
|
|
2733a1 |
+ * @param fi file info iterator (or NULL)
|
|
|
2733a1 |
+ * @param path file object path
|
|
|
2733a1 |
+ * @param file_mode file object mode
|
|
|
2733a1 |
+ * @param op file operation + associated flags
|
|
|
2733a1 |
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+RPM_GNUC_INTERNAL
|
|
|
2733a1 |
+rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,
|
|
|
2733a1 |
+ const char* path, mode_t file_mode,
|
|
|
2733a1 |
+ rpmFsmOp op);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+RPM_GNUC_INTERNAL
|
|
|
2733a1 |
+rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload,
|
|
|
2733a1 |
+ rpmfiles files, rpmfi *fi);
|
|
|
2733a1 |
#ifdef __cplusplus
|
|
|
2733a1 |
}
|
|
|
2733a1 |
#endif
|
|
|
2733a1 |
diff --git a/lib/rpmte.c b/lib/rpmte.c
|
|
|
2733a1 |
index d31152a..642e809 100644
|
|
|
2733a1 |
--- a/lib/rpmte.c
|
|
|
2733a1 |
+++ b/lib/rpmte.c
|
|
|
2733a1 |
@@ -437,6 +437,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd)
|
|
|
2733a1 |
return NULL;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
+FD_t rpmteFd(rpmte te)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ return (te != NULL ? te->fd : NULL);
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
fnpyKey rpmteKey(rpmte te)
|
|
|
2733a1 |
{
|
|
|
2733a1 |
return (te != NULL ? te->key : NULL);
|
|
|
2733a1 |
diff --git a/lib/transaction.c b/lib/transaction.c
|
|
|
2733a1 |
index 70d2587..1e98f11 100644
|
|
|
2733a1 |
--- a/lib/transaction.c
|
|
|
2733a1 |
+++ b/lib/transaction.c
|
|
|
2733a1 |
@@ -28,6 +28,7 @@
|
|
|
2733a1 |
#include <rpm/rpmstring.h>
|
|
|
2733a1 |
#include <rpm/rpmsq.h>
|
|
|
2733a1 |
#include <rpm/rpmkeyring.h>
|
|
|
2733a1 |
+#include <rpm/rpmextents_internal.h>
|
|
|
2733a1 |
|
|
|
2733a1 |
#include "fprint.h"
|
|
|
2733a1 |
#include "misc.h"
|
|
|
2733a1 |
@@ -1292,19 +1293,25 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)
|
|
|
2733a1 |
|
|
|
2733a1 |
rpmtsNotify(ts, p, RPMCALLBACK_VERIFY_PROGRESS, oc++, total);
|
|
|
2733a1 |
FD_t fd = rpmtsNotify(ts, p, RPMCALLBACK_INST_OPEN_FILE, 0, 0);
|
|
|
2733a1 |
- if (fd != NULL) {
|
|
|
2733a1 |
- prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg);
|
|
|
2733a1 |
- rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0);
|
|
|
2733a1 |
+ if(fd != NULL && isTranscodedRpm(fd) == RPMRC_OK) {
|
|
|
2733a1 |
+ /* Transcoded RPMs are validated at transcoding time */
|
|
|
2733a1 |
+ prc = RPMRC_OK;
|
|
|
2733a1 |
+ verified = 1;
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ if (fd != NULL) {
|
|
|
2733a1 |
+ prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg);
|
|
|
2733a1 |
+ rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (prc == RPMRC_OK)
|
|
|
2733a1 |
+ prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* Record verify result */
|
|
|
2733a1 |
+ if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK)
|
|
|
2733a1 |
+ verified |= RPMSIG_SIGNATURE_TYPE;
|
|
|
2733a1 |
+ if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK)
|
|
|
2733a1 |
+ verified |= RPMSIG_DIGEST_TYPE;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
- if (prc == RPMRC_OK)
|
|
|
2733a1 |
- prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);
|
|
|
2733a1 |
-
|
|
|
2733a1 |
- /* Record verify result */
|
|
|
2733a1 |
- if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK)
|
|
|
2733a1 |
- verified |= RPMSIG_SIGNATURE_TYPE;
|
|
|
2733a1 |
- if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK)
|
|
|
2733a1 |
- verified |= RPMSIG_DIGEST_TYPE;
|
|
|
2733a1 |
rpmteSetVerified(p, verified);
|
|
|
2733a1 |
|
|
|
2733a1 |
if (prc)
|
|
|
2733a1 |
diff --git a/macros.in b/macros.in
|
|
|
2733a1 |
index 7eb3d2b..df7defe 100644
|
|
|
2733a1 |
--- a/macros.in
|
|
|
2733a1 |
+++ b/macros.in
|
|
|
2733a1 |
@@ -1188,6 +1188,7 @@ Supplements: (%{name} = %{version}-%{release} and langpacks-%{1})\
|
|
|
2733a1 |
|
|
|
2733a1 |
# Transaction plugin macros
|
|
|
2733a1 |
%__plugindir %{_libdir}/rpm-plugins
|
|
|
2733a1 |
+%__transaction_reflink %{__plugindir}/reflink.so
|
|
|
2733a1 |
%__transaction_systemd_inhibit %{__plugindir}/systemd_inhibit.so
|
|
|
2733a1 |
%__transaction_selinux %{__plugindir}/selinux.so
|
|
|
2733a1 |
%__transaction_syslog %{__plugindir}/syslog.so
|
|
|
2733a1 |
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
|
|
|
2733a1 |
index c2c112b..ed63a43 100644
|
|
|
2733a1 |
--- a/plugins/CMakeLists.txt
|
|
|
2733a1 |
+++ b/plugins/CMakeLists.txt
|
|
|
2733a1 |
@@ -1,5 +1,6 @@
|
|
|
2733a1 |
add_library(prioreset MODULE prioreset.c)
|
|
|
2733a1 |
add_library(syslog MODULE syslog.c)
|
|
|
2733a1 |
+add_library(reflink MODULE reflink.c)
|
|
|
2733a1 |
|
|
|
2733a1 |
if(WITH_SELINUX)
|
|
|
2733a1 |
add_library(selinux MODULE selinux.c)
|
|
|
2733a1 |
@@ -44,7 +45,6 @@ get_property(plugins DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
|
|
|
2733a1 |
foreach(plugin ${plugins})
|
|
|
2733a1 |
target_link_libraries(${plugin} PRIVATE librpmio librpm ${Intl_LIBRARIES})
|
|
|
2733a1 |
# XX this is wrong, but required while rpmplugin.h is there
|
|
|
2733a1 |
- target_include_directories(${plugin} PRIVATE ${CMAKE_SOURCE_DIR}/lib ${Intl_INCLUDE_DIRS})
|
|
|
2733a1 |
+ target_include_directories(${plugin} PRIVATE ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/rpmio ${Intl_INCLUDE_DIRS})
|
|
|
2733a1 |
install(TARGETS ${plugin} DESTINATION ${plugindir})
|
|
|
2733a1 |
endforeach()
|
|
|
2733a1 |
-
|
|
|
2733a1 |
diff --git a/plugins/reflink.c b/plugins/reflink.c
|
|
|
2733a1 |
new file mode 100644
|
|
|
2733a1 |
index 0000000..7ce3a9f
|
|
|
2733a1 |
--- /dev/null
|
|
|
2733a1 |
+++ b/plugins/reflink.c
|
|
|
2733a1 |
@@ -0,0 +1,401 @@
|
|
|
2733a1 |
+#include "system.h"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include <errno.h>
|
|
|
2733a1 |
+#include <sys/resource.h>
|
|
|
2733a1 |
+#include <unistd.h>
|
|
|
2733a1 |
+#include <sys/types.h>
|
|
|
2733a1 |
+#include <sys/stat.h>
|
|
|
2733a1 |
+#include <fcntl.h>
|
|
|
2733a1 |
+#if defined(__linux__)
|
|
|
2733a1 |
+#include <linux/fs.h> /* For FICLONE */
|
|
|
2733a1 |
+#endif
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include <rpm/rpmlog.h>
|
|
|
2733a1 |
+#include <rpm/rpmlib.h>
|
|
|
2733a1 |
+#include <rpm/rpmextents_internal.h>
|
|
|
2733a1 |
+#include <rpm/rpmfileutil.h>
|
|
|
2733a1 |
+#include "rpmplugin.h"
|
|
|
2733a1 |
+#include "rpmte_internal.h"
|
|
|
2733a1 |
+#include "rpmio_internal.h"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include "debug.h"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include <sys/ioctl.h>
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/* use hash table to remember inode -> ix (for rpmfilesFN(ix)) lookups */
|
|
|
2733a1 |
+#undef HASHTYPE
|
|
|
2733a1 |
+#undef HTKEYTYPE
|
|
|
2733a1 |
+#undef HTDATATYPE
|
|
|
2733a1 |
+#define HASHTYPE inodeIndexHash
|
|
|
2733a1 |
+#define HTKEYTYPE rpm_ino_t
|
|
|
2733a1 |
+#define HTDATATYPE const char *
|
|
|
2733a1 |
+#include "rpmhash.H"
|
|
|
2733a1 |
+#include "rpmhash.C"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/* We use this in find to indicate a key wasn't found. This is an
|
|
|
2733a1 |
+ * unrecoverable error, but we can at least show a decent error. 0 is never a
|
|
|
2733a1 |
+ * valid offset because it's the offset of the start of the file.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+#define NOT_FOUND 0
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#define BUFFER_SIZE (1024 * 128)
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+struct reflink_state_s {
|
|
|
2733a1 |
+ /* Stuff that's used across rpms */
|
|
|
2733a1 |
+ long fundamental_block_size;
|
|
|
2733a1 |
+ char *buffer;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* stuff that's used/updated per psm */
|
|
|
2733a1 |
+ uint32_t keys, keysize;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) */
|
|
|
2733a1 |
+ unsigned char *table;
|
|
|
2733a1 |
+ FD_t fd;
|
|
|
2733a1 |
+ rpmfiles files;
|
|
|
2733a1 |
+ inodeIndexHash inodeIndexes;
|
|
|
2733a1 |
+ int transcoded;
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+typedef struct reflink_state_s * reflink_state;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/*
|
|
|
2733a1 |
+ * bsearch_r: implements a re-entrant version of stdlib's bsearch.
|
|
|
2733a1 |
+ * code taken and adapted from /usr/include/bits/stdlib-bsearch.h
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+static inline void *
|
|
|
2733a1 |
+bsearch_r (const void *__key, const void *__base, size_t __nmemb, size_t __size,
|
|
|
2733a1 |
+ __compar_d_fn_t __compar, void *__arg)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ size_t __l, __u, __idx;
|
|
|
2733a1 |
+ const void *__p;
|
|
|
2733a1 |
+ int __comparison;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ __l = 0;
|
|
|
2733a1 |
+ __u = __nmemb;
|
|
|
2733a1 |
+ while (__l < __u)
|
|
|
2733a1 |
+ {
|
|
|
2733a1 |
+ __idx = (__l + __u) / 2;
|
|
|
2733a1 |
+ __p = (const void *) (((const char *) __base) + (__idx * __size));
|
|
|
2733a1 |
+ __comparison = (*__compar) (__key, __p, __arg);
|
|
|
2733a1 |
+ if (__comparison < 0)
|
|
|
2733a1 |
+ __u = __idx;
|
|
|
2733a1 |
+ else if (__comparison > 0)
|
|
|
2733a1 |
+ __l = __idx + 1;
|
|
|
2733a1 |
+ else
|
|
|
2733a1 |
+ {
|
|
|
2733a1 |
+#if __GNUC_PREREQ(4, 6)
|
|
|
2733a1 |
+# pragma GCC diagnostic push
|
|
|
2733a1 |
+# pragma GCC diagnostic ignored "-Wcast-qual"
|
|
|
2733a1 |
+#endif
|
|
|
2733a1 |
+ return (void *) __p;
|
|
|
2733a1 |
+#if __GNUC_PREREQ(4, 6)
|
|
|
2733a1 |
+# pragma GCC diagnostic pop
|
|
|
2733a1 |
+#endif
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return NULL;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static int cmpdigest(const void *k1, const void *k2, void *data) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
|
|
|
2733a1 |
+ return memcmp(k1, k2, *(int *)data);
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static int inodeCmp(rpm_ino_t a, rpm_ino_t b)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ return (a != b);
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static unsigned int inodeId(rpm_ino_t a)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ /* rpm_ino_t is uint32_t so maps safely to unsigned int */
|
|
|
2733a1 |
+ return (unsigned int)a;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) {
|
|
|
2733a1 |
+ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s));
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset
|
|
|
2733a1 |
+ * and length arguments to be aligned to the fundamental block size.
|
|
|
2733a1 |
+ *
|
|
|
2733a1 |
+ * The value of "fundamental block size" is directly related to the
|
|
|
2733a1 |
+ * system's page size, so we should use that.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ state->fundamental_block_size = sysconf(_SC_PAGESIZE);
|
|
|
2733a1 |
+ state->buffer = rcalloc(1, BUFFER_SIZE);
|
|
|
2733a1 |
+ rpmPluginSetData(plugin, state);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static void reflink_cleanup(rpmPlugin plugin) {
|
|
|
2733a1 |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
2733a1 |
+ free(state->buffer);
|
|
|
2733a1 |
+ free(state);
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {
|
|
|
2733a1 |
+ rpmRC rc;
|
|
|
2733a1 |
+ size_t len;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
2733a1 |
+ state->fd = rpmteFd(te);
|
|
|
2733a1 |
+ if (state->fd == 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n"));
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rpm_loff_t current = Ftell(state->fd);
|
|
|
2733a1 |
+ rc = isTranscodedRpm(state->fd);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ switch(rc){
|
|
|
2733a1 |
+ // Fail to parse the file, fail the plugin.
|
|
|
2733a1 |
+ case RPMRC_FAIL:
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ // This is not a transcoded file, do nothing.
|
|
|
2733a1 |
+ case RPMRC_NOTFOUND:
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+ default:
|
|
|
2733a1 |
+ break;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n"));
|
|
|
2733a1 |
+ state->transcoded = 1;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ state->files = rpmteFiles(te);
|
|
|
2733a1 |
+ /* tail of file contains offset_table, offset_checksums then magic */
|
|
|
2733a1 |
+ if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(extents_magic_t)), SEEK_END) < 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"),
|
|
|
2733a1 |
+ state->fd);
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpm_loff_t table_start;
|
|
|
2733a1 |
+ len = sizeof(table_start);
|
|
|
2733a1 |
+ if (Fread(&table_start, len, 1, state->fd) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (Fseek(state->fd, table_start, SEEK_SET) < 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ len = sizeof(state->keys);
|
|
|
2733a1 |
+ if (Fread(&state->keys, len, 1, state->fd) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ len = sizeof(state->keysize);
|
|
|
2733a1 |
+ if (Fread(&state->keysize, len, 1, state->fd) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpmlog(
|
|
|
2733a1 |
+ RPMLOG_DEBUG,
|
|
|
2733a1 |
+ _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"),
|
|
|
2733a1 |
+ table_start, state->keys, state->keysize
|
|
|
2733a1 |
+ );
|
|
|
2733a1 |
+ /* now get digest table if there is a reason to have one. */
|
|
|
2733a1 |
+ if (state->keys == 0 || state->keysize == 0) {
|
|
|
2733a1 |
+ /* no files (or no digests(!)) */
|
|
|
2733a1 |
+ state->table = NULL;
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t));
|
|
|
2733a1 |
+ state->table = rcalloc(1, table_size);
|
|
|
2733a1 |
+ if (Fread(state->table, table_size, 1, state->fd) != table_size) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ state->inodeIndexes = inodeIndexHashCreate(
|
|
|
2733a1 |
+ state->keys, inodeId, inodeCmp, NULL, (inodeIndexHashFreeData)free
|
|
|
2733a1 |
+ );
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* Seek back to original location.
|
|
|
2733a1 |
+ * Might not be needed if we seek to offset immediately
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("reflink: unable to seek back to original location\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
2733a1 |
+ state->files = rpmfilesFree(state->files);
|
|
|
2733a1 |
+ if (state->table) {
|
|
|
2733a1 |
+ free(state->table);
|
|
|
2733a1 |
+ state->table = NULL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (state->inodeIndexes) {
|
|
|
2733a1 |
+ inodeIndexHashFree(state->inodeIndexes);
|
|
|
2733a1 |
+ state->inodeIndexes = NULL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ state->transcoded = 0;
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/* have a prototype, warnings system */
|
|
|
2733a1 |
+rpm_loff_t find(const unsigned char *digest, reflink_state state);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpm_loff_t find(const unsigned char *digest, reflink_state state) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_DEBUG,
|
|
|
2733a1 |
+ _("reflink: bsearch_r(key=%p, base=%p, nmemb=%d, size=%lu)\n"),
|
|
|
2733a1 |
+ digest, state->table, state->keys,
|
|
|
2733a1 |
+ state->keysize + sizeof(rpm_loff_t));
|
|
|
2733a1 |
+ char *entry = bsearch_r(digest, state->table, state->keys,
|
|
|
2733a1 |
+ state->keysize + sizeof(rpm_loff_t), cmpdigest,
|
|
|
2733a1 |
+ &state->keysize);
|
|
|
2733a1 |
+ if (entry == NULL) {
|
|
|
2733a1 |
+ return NOT_FOUND;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize);
|
|
|
2733a1 |
+ return offset;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* path,
|
|
|
2733a1 |
+ mode_t file_mode, rpmFsmOp op)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ struct file_clone_range fcr;
|
|
|
2733a1 |
+ rpm_loff_t size;
|
|
|
2733a1 |
+ int dst, rc;
|
|
|
2733a1 |
+ const char **hl_target = NULL;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
2733a1 |
+ if (state->table == NULL) {
|
|
|
2733a1 |
+ /* no table means rpm is not in reflink format, so leave. Now. */
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (op == FA_TOUCH) {
|
|
|
2733a1 |
+ /* we're not overwriting an existing file. */
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ fcr.dest_offset = 0;
|
|
|
2733a1 |
+ if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) {
|
|
|
2733a1 |
+ rpm_ino_t inode = rpmfiFInode(fi);
|
|
|
2733a1 |
+ /* check for hard link entry in table. GetEntry overwrites hlix with
|
|
|
2733a1 |
+ * the address of the first match.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hl_target,
|
|
|
2733a1 |
+ NULL, NULL)) {
|
|
|
2733a1 |
+ /* entry is in table, use hard link */
|
|
|
2733a1 |
+ if (link(hl_target[0], path) != 0) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("reflink: Unable to hard link %s -> %s due to %s\n"),
|
|
|
2733a1 |
+ hl_target[0], path, strerror(errno));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return RPMRC_PLUGIN_CONTENTS;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ /* if we didn't hard link, then we'll track this inode as being
|
|
|
2733a1 |
+ * created soon
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ if (rpmfiFNlink(fi) > 1) {
|
|
|
2733a1 |
+ /* minor optimization: only store files with more than one link */
|
|
|
2733a1 |
+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path));
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ /* derived from wfd_open in fsm.c */
|
|
|
2733a1 |
+ mode_t old_umask = umask(0577);
|
|
|
2733a1 |
+ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
|
|
|
2733a1 |
+ umask(old_umask);
|
|
|
2733a1 |
+ if (dst == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("reflink: Unable to open %s for writing due to %s, flags = %x\n"),
|
|
|
2733a1 |
+ path, strerror(errno), rpmfiFFlags(fi));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ size = rpmfiFSize(fi);
|
|
|
2733a1 |
+ if (size > 0) {
|
|
|
2733a1 |
+ /* round src_length down to fundamental_block_size multiple */
|
|
|
2733a1 |
+ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size;
|
|
|
2733a1 |
+ if ((size % state->fundamental_block_size) > 0) {
|
|
|
2733a1 |
+ /* round up to next fundamental_block_size. We expect the data
|
|
|
2733a1 |
+ * in the rpm to be similarly padded.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ fcr.src_length += state->fundamental_block_size;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ fcr.src_fd = Fileno(state->fd);
|
|
|
2733a1 |
+ if (fcr.src_fd == -1) {
|
|
|
2733a1 |
+ close(dst);
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state);
|
|
|
2733a1 |
+ if (fcr.src_offset == NOT_FOUND) {
|
|
|
2733a1 |
+ close(dst);
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpmlog(RPMLOG_DEBUG,
|
|
|
2733a1 |
+ _("reflink: Reflinking %llu bytes at %llu to %s orig size=%ld, file=%lld\n"),
|
|
|
2733a1 |
+ fcr.src_length, fcr.src_offset, path, size, fcr.src_fd);
|
|
|
2733a1 |
+ rc = ioctl(dst, FICLONERANGE, &fcr;;
|
|
|
2733a1 |
+ if (rc) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_WARNING,
|
|
|
2733a1 |
+ _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"),
|
|
|
2733a1 |
+ path, rc, errno, strerror(errno));
|
|
|
2733a1 |
+ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) {
|
|
|
2733a1 |
+ close(dst);
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("reflink: unable to seek on copying bits\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpm_loff_t left = size;
|
|
|
2733a1 |
+ size_t len, read, written;
|
|
|
2733a1 |
+ while (left) {
|
|
|
2733a1 |
+ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left);
|
|
|
2733a1 |
+ read = Fread(state->buffer, len, 1, state->fd);
|
|
|
2733a1 |
+ if (read != len) {
|
|
|
2733a1 |
+ close(dst);
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("reflink: short read on copying bits\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ written = write(dst, state->buffer, len);
|
|
|
2733a1 |
+ if (read != written) {
|
|
|
2733a1 |
+ close(dst);
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("reflink: short write on copying bits\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ left -= len;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ /* reflink worked, so truncate */
|
|
|
2733a1 |
+ rc = ftruncate(dst, size);
|
|
|
2733a1 |
+ if (rc) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("reflink: Unable to truncate %s to %ld due to %s\n"),
|
|
|
2733a1 |
+ path, size, strerror(errno));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ close(dst);
|
|
|
2733a1 |
+ return RPMRC_PLUGIN_CONTENTS;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC reflink_fsm_file_archive_reader(rpmPlugin plugin, FD_t payload,
|
|
|
2733a1 |
+ rpmfiles files, rpmfi *fi) {
|
|
|
2733a1 |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
2733a1 |
+ if(state->transcoded) {
|
|
|
2733a1 |
+ *fi = rpmfilesIter(files, RPMFI_ITER_FWD);
|
|
|
2733a1 |
+ return RPMRC_PLUGIN_CONTENTS;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return RPMRC_OK;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+struct rpmPluginHooks_s reflink_hooks = {
|
|
|
2733a1 |
+ .init = reflink_init,
|
|
|
2733a1 |
+ .cleanup = reflink_cleanup,
|
|
|
2733a1 |
+ .psm_pre = reflink_psm_pre,
|
|
|
2733a1 |
+ .psm_post = reflink_psm_post,
|
|
|
2733a1 |
+ .fsm_file_install = reflink_fsm_file_install,
|
|
|
2733a1 |
+ .fsm_file_archive_reader = reflink_fsm_file_archive_reader,
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
|
|
|
2733a1 |
index f545213..5b2ad78 100644
|
|
|
2733a1 |
--- a/rpmio/rpmpgp.c
|
|
|
2733a1 |
+++ b/rpmio/rpmpgp.c
|
|
|
2733a1 |
@@ -81,3 +81,31 @@ pgpArmor pgpReadPkts(const char * fn, uint8_t ** pkt, size_t * pktlen)
|
|
|
2733a1 |
free(b);
|
|
|
2733a1 |
return ec;
|
|
|
2733a1 |
}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/** \ingroup rpmpgp
|
|
|
2733a1 |
+ * Return value of an OpenPGP string.
|
|
|
2733a1 |
+ * @param vs table of (string,value) pairs
|
|
|
2733a1 |
+ * @param s string token to lookup
|
|
|
2733a1 |
+ * @param se end-of-string address
|
|
|
2733a1 |
+ * @return byte value
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+static inline
|
|
|
2733a1 |
+int pgpValTok(pgpValTbl vs, const char * s, const char * se)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ do {
|
|
|
2733a1 |
+ size_t vlen = strlen(vs->str);
|
|
|
2733a1 |
+ if (vlen <= (se-s) && rstreqn(s, vs->str, vlen))
|
|
|
2733a1 |
+ break;
|
|
|
2733a1 |
+ } while ((++vs)->val != -1);
|
|
|
2733a1 |
+ return vs->val;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+int pgpStringVal(pgpValType type, const char *str, uint8_t *val)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ pgpValTbl tbl = pgpValTable(type);
|
|
|
2733a1 |
+ if (tbl == NULL) return -1;
|
|
|
2733a1 |
+ int v = pgpValTok(tbl, str, str + strlen(str));
|
|
|
2733a1 |
+ if (v == -1) return -1;
|
|
|
2733a1 |
+ *val = (uint8_t)v;
|
|
|
2733a1 |
+ return 0;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
diff --git a/rpmio/rpmpgp_internal.c b/rpmio/rpmpgp_internal.c
|
|
|
2733a1 |
index 0e38946..0cfe9b9 100644
|
|
|
2733a1 |
--- a/rpmio/rpmpgp_internal.c
|
|
|
2733a1 |
+++ b/rpmio/rpmpgp_internal.c
|
|
|
2733a1 |
@@ -88,24 +88,6 @@ static void pgpPrtTime(const char * pre, const uint8_t *p, size_t plen)
|
|
|
2733a1 |
}
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
-/** \ingroup rpmpgp
|
|
|
2733a1 |
- * Return value of an OpenPGP string.
|
|
|
2733a1 |
- * @param vs table of (string,value) pairs
|
|
|
2733a1 |
- * @param s string token to lookup
|
|
|
2733a1 |
- * @param se end-of-string address
|
|
|
2733a1 |
- * @return byte value
|
|
|
2733a1 |
- */
|
|
|
2733a1 |
-static inline
|
|
|
2733a1 |
-int pgpValTok(pgpValTbl vs, const char * s, const char * se)
|
|
|
2733a1 |
-{
|
|
|
2733a1 |
- do {
|
|
|
2733a1 |
- size_t vlen = strlen(vs->str);
|
|
|
2733a1 |
- if (vlen <= (se-s) && rstreqn(s, vs->str, vlen))
|
|
|
2733a1 |
- break;
|
|
|
2733a1 |
- } while ((++vs)->val != -1);
|
|
|
2733a1 |
- return vs->val;
|
|
|
2733a1 |
-}
|
|
|
2733a1 |
-
|
|
|
2733a1 |
/** \ingroup rpmpgp
|
|
|
2733a1 |
* Decode length from 1, 2, or 5 octet body length encoding, used in
|
|
|
2733a1 |
* new format packet headers and V4 signature subpackets.
|
|
|
2733a1 |
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
|
|
|
2733a1 |
index 07749bc..8f8ae64 100644
|
|
|
2733a1 |
--- a/scripts/CMakeLists.txt
|
|
|
2733a1 |
+++ b/scripts/CMakeLists.txt
|
|
|
2733a1 |
@@ -12,7 +12,7 @@ install(PROGRAMS
|
|
|
2733a1 |
rpm_macros_provides.sh
|
|
|
2733a1 |
rpmdb_dump rpmdb_load
|
|
|
2733a1 |
rpm2cpio.sh tgpg
|
|
|
2733a1 |
- sysusers.sh
|
|
|
2733a1 |
+ sysusers.sh rpm2extents_dump
|
|
|
2733a1 |
DESTINATION ${RPM_CONFIGDIR}
|
|
|
2733a1 |
)
|
|
|
2733a1 |
install(FILES
|
|
|
2733a1 |
diff --git a/scripts/rpm2extents_dump b/scripts/rpm2extents_dump
|
|
|
2733a1 |
new file mode 100755
|
|
|
2733a1 |
index 0000000..596a59a
|
|
|
2733a1 |
--- /dev/null
|
|
|
2733a1 |
+++ b/scripts/rpm2extents_dump
|
|
|
2733a1 |
@@ -0,0 +1,94 @@
|
|
|
2733a1 |
+#!/usr/bin/env python3
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+import argparse
|
|
|
2733a1 |
+import binascii
|
|
|
2733a1 |
+import os
|
|
|
2733a1 |
+import struct
|
|
|
2733a1 |
+import sys
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+MAGIC_SIZE = 8
|
|
|
2733a1 |
+MAGIC_STR = b'KWTSH100'
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+POS_SIZE = 8
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+def keep_position(func):
|
|
|
2733a1 |
+ def wrapper(*args, **kwargs):
|
|
|
2733a1 |
+ curr = args[0].tell()
|
|
|
2733a1 |
+ res = func(*args, **kwargs)
|
|
|
2733a1 |
+ f.seek(curr, os.SEEK_SET)
|
|
|
2733a1 |
+ return res
|
|
|
2733a1 |
+ return wrapper
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+def read_validation_digest(f, validation_offset):
|
|
|
2733a1 |
+ digests = []
|
|
|
2733a1 |
+ # validation
|
|
|
2733a1 |
+ f.seek(validation_offset, os.SEEK_SET)
|
|
|
2733a1 |
+ val_content_len, val_digests_num = struct.unpack('=QI', f.read(8+4))
|
|
|
2733a1 |
+ for i in range(val_digests_num):
|
|
|
2733a1 |
+ algo_name_len, digest_len = struct.unpack('=II', f.read(8))
|
|
|
2733a1 |
+ algo_name, digest = struct.unpack(f'{algo_name_len}s{digest_len}s', f.read(algo_name_len+digest_len))
|
|
|
2733a1 |
+ digests.append((algo_name, binascii.hexlify(digest)))
|
|
|
2733a1 |
+ return digests
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+def read_digests_table(f, digest_offset):
|
|
|
2733a1 |
+ digests = []
|
|
|
2733a1 |
+ # validation
|
|
|
2733a1 |
+ f.seek(digest_offset, os.SEEK_SET)
|
|
|
2733a1 |
+ table_len, digest_len = struct.unpack('=II', f.read(8))
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ for i in range(table_len):
|
|
|
2733a1 |
+ digest, pos = struct.unpack(f'{digest_len}sQ', f.read(digest_len + 8))
|
|
|
2733a1 |
+ digests.append((pos, binascii.hexlify(digest)))
|
|
|
2733a1 |
+ return digests
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+def read_signature_output(f, signature_offset):
|
|
|
2733a1 |
+ f.seek(signature_offset, os.SEEK_SET)
|
|
|
2733a1 |
+ signature_rc, signature_output_len = struct.unpack('=IQ', f.read(12))
|
|
|
2733a1 |
+ return signature_rc, f.read(signature_output_len)
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+@keep_position
|
|
|
2733a1 |
+def parse_file(f):
|
|
|
2733a1 |
+ digests = []
|
|
|
2733a1 |
+ pos_table_offset = f.seek(-8 - 3*POS_SIZE, os.SEEK_END)
|
|
|
2733a1 |
+ signature_offset, digest_offset, validation_offset = struct.unpack('=QQQ', f.read(3*POS_SIZE))
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ validation_digests = read_validation_digest(f, validation_offset)
|
|
|
2733a1 |
+ digests_table = read_digests_table(f, digest_offset)
|
|
|
2733a1 |
+ signature_ouput = read_signature_output(f, signature_offset)
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return validation_digests, digests_table, signature_ouput
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+@keep_position
|
|
|
2733a1 |
+def is_transcoded(f):
|
|
|
2733a1 |
+ f.seek(-MAGIC_SIZE, os.SEEK_END)
|
|
|
2733a1 |
+ magic = f.read(MAGIC_SIZE)
|
|
|
2733a1 |
+ return magic == MAGIC_STR
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+def arg_parse():
|
|
|
2733a1 |
+ parser = argparse.ArgumentParser()
|
|
|
2733a1 |
+ parser.add_argument('--dump-signature', action='store_true')
|
|
|
2733a1 |
+ parser.add_argument('--dump-file-digest-table', action='store_true')
|
|
|
2733a1 |
+ parser.add_argument('--dump-digests', action='store_true')
|
|
|
2733a1 |
+ parser.add_argument('file')
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return parser.parse_args()
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+if __name__ == '__main__':
|
|
|
2733a1 |
+ args = arg_parse()
|
|
|
2733a1 |
+ f = open(args.file, 'rb')
|
|
|
2733a1 |
+ if not is_transcoded(f):
|
|
|
2733a1 |
+ sys.exit(1)
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ validation_digests, digests_table, signature_output = parse_file(f)
|
|
|
2733a1 |
+ if(args.dump_file_digest_table):
|
|
|
2733a1 |
+ for digest in digests_table:
|
|
|
2733a1 |
+ print(f"FileDigest {hex(digest[0])}: {digest[1]}")
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if(args.dump_digests):
|
|
|
2733a1 |
+ for validation_digest in validation_digests:
|
|
|
2733a1 |
+ print(f"HeaderDigest {validation_digest[0]} {validation_digest[1]}")
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if(args.dump_signature):
|
|
|
2733a1 |
+ print(f"RPMSignOutput RC {signature_output[0]}\nRPMSignOutput Content {signature_output[1].decode()}")
|
|
|
2733a1 |
+
|
|
|
2733a1 |
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
|
|
|
2733a1 |
index a6afbc0..bee3b64 100644
|
|
|
2733a1 |
--- a/tests/CMakeLists.txt
|
|
|
2733a1 |
+++ b/tests/CMakeLists.txt
|
|
|
2733a1 |
@@ -51,6 +51,7 @@ set(TESTSUITE_AT
|
|
|
2733a1 |
rpmvfylevel.at
|
|
|
2733a1 |
rpmpgp.at
|
|
|
2733a1 |
rpmdevel.at
|
|
|
2733a1 |
+ rpm2extents.at
|
|
|
2733a1 |
)
|
|
|
2733a1 |
|
|
|
2733a1 |
set(TESTPROGS rpmpgpcheck rpmpgppubkeyfingerprint)
|
|
|
2733a1 |
diff --git a/tests/atlocal.in b/tests/atlocal.in
|
|
|
2733a1 |
index a5faeed..9930cb4 100644
|
|
|
2733a1 |
--- a/tests/atlocal.in
|
|
|
2733a1 |
+++ b/tests/atlocal.in
|
|
|
2733a1 |
@@ -100,6 +100,19 @@ snapshot()
|
|
|
2733a1 |
esac
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
+FSTYPE=$(stat -f -c %T /)
|
|
|
2733a1 |
+REFLINKABLE_FS=("xfs" "brtfs")
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+REFLINK_DISABLED=true;
|
|
|
2733a1 |
+for item in "${REFLINKABLE_FS[@]}"
|
|
|
2733a1 |
+do
|
|
|
2733a1 |
+ if test "${FSTYPE}" = "${item}"
|
|
|
2733a1 |
+ then
|
|
|
2733a1 |
+ REFLINK_DISABLED=false;
|
|
|
2733a1 |
+ break
|
|
|
2733a1 |
+ fi
|
|
|
2733a1 |
+done
|
|
|
2733a1 |
+
|
|
|
2733a1 |
setup_env()
|
|
|
2733a1 |
{
|
|
|
2733a1 |
if [ -d tree ]; then
|
|
|
2733a1 |
@@ -138,6 +151,14 @@ runroot()
|
|
|
2733a1 |
--nouserns
|
|
|
2733a1 |
}
|
|
|
2733a1 |
|
|
|
2733a1 |
+function runroot_plugins()
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ setup_env
|
|
|
2733a1 |
+ (unset RPM_CONFIGDIR RPM_POPTEXEC_PATH; cd ${RPMTEST} && \
|
|
|
2733a1 |
+ MAGIC="/magic/magic" FAKECHROOT_BASE="${RPMTEST}" fakechroot "$@" --define "_buildhost testhost" --define "_topdir /build" --nouserns
|
|
|
2733a1 |
+ )
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
runroot_other()
|
|
|
2733a1 |
{
|
|
|
2733a1 |
setup_env
|
|
|
2733a1 |
diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at
|
|
|
2733a1 |
new file mode 100644
|
|
|
2733a1 |
index 0000000..c9c79c5
|
|
|
2733a1 |
--- /dev/null
|
|
|
2733a1 |
+++ b/tests/rpm2extents.at
|
|
|
2733a1 |
@@ -0,0 +1,151 @@
|
|
|
2733a1 |
+# rpm2extents.at: Some very basic checks
|
|
|
2733a1 |
+#
|
|
|
2733a1 |
+# Copyright (C) 2022 Manu Bretelle <chantr4@gmail.com>
|
|
|
2733a1 |
+#
|
|
|
2733a1 |
+# This program is free software; you can redistribute it and/or modify
|
|
|
2733a1 |
+# it under the terms of the GNU General Public License as published by
|
|
|
2733a1 |
+# the Free Software Foundation; either version 2 of the License, or
|
|
|
2733a1 |
+# (at your option) any later version.
|
|
|
2733a1 |
+#
|
|
|
2733a1 |
+# This program is distributed in the hope that it will be useful,
|
|
|
2733a1 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
2733a1 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
2733a1 |
+# GNU General Public License for more details.
|
|
|
2733a1 |
+#
|
|
|
2733a1 |
+# You should have received a copy of the GNU General Public License
|
|
|
2733a1 |
+# along with this program; if not, write to the Free Software
|
|
|
2733a1 |
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+AT_BANNER([rpm2extents tests])
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+# ------------------------------
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+# check that transcoder write magic at the end
|
|
|
2733a1 |
+AT_SETUP([rpm2extents magic])
|
|
|
2733a1 |
+AT_KEYWORDS([rpm2extents])
|
|
|
2733a1 |
+AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | tail -c8],
|
|
|
2733a1 |
+[0],
|
|
|
2733a1 |
+[KWTSH100],
|
|
|
2733a1 |
+[ignore])
|
|
|
2733a1 |
+AT_CLEANUP
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+# Check that transcoder writes checksig return code and content.
|
|
|
2733a1 |
+#
|
|
|
2733a1 |
+AT_SETUP([rpm2extents signature])
|
|
|
2733a1 |
+AT_KEYWORDS([rpm2extents])
|
|
|
2733a1 |
+AT_CHECK([
|
|
|
2733a1 |
+RPMDB_INIT
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null
|
|
|
2733a1 |
+rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm
|
|
|
2733a1 |
+runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub
|
|
|
2733a1 |
+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm
|
|
|
2733a1 |
+rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm
|
|
|
2733a1 |
+],
|
|
|
2733a1 |
+[0],
|
|
|
2733a1 |
+[RPMSignOutput RC 2
|
|
|
2733a1 |
+RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY
|
|
|
2733a1 |
+ Header SHA256 digest: OK
|
|
|
2733a1 |
+ Header SHA1 digest: OK
|
|
|
2733a1 |
+ Payload SHA256 digest: OK
|
|
|
2733a1 |
+ V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY
|
|
|
2733a1 |
+ MD5 digest: OK
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+RPMSignOutput RC 0
|
|
|
2733a1 |
+RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK
|
|
|
2733a1 |
+ Header SHA256 digest: OK
|
|
|
2733a1 |
+ Header SHA1 digest: OK
|
|
|
2733a1 |
+ Payload SHA256 digest: OK
|
|
|
2733a1 |
+ V4 RSA/SHA256 Signature, key ID 1964c5fc: OK
|
|
|
2733a1 |
+ MD5 digest: OK
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+],
|
|
|
2733a1 |
+[])
|
|
|
2733a1 |
+AT_CLEANUP
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+AT_SETUP([rpm2extents signature verification])
|
|
|
2733a1 |
+AT_KEYWORDS([rpm2extents])
|
|
|
2733a1 |
+AT_CHECK([
|
|
|
2733a1 |
+RPMDB_INIT
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null
|
|
|
2733a1 |
+runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $?
|
|
|
2733a1 |
+runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub
|
|
|
2733a1 |
+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm
|
|
|
2733a1 |
+runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $?
|
|
|
2733a1 |
+],
|
|
|
2733a1 |
+[0],
|
|
|
2733a1 |
+[/tmp/hello-2.0-1.x86_64-signed.rpm:
|
|
|
2733a1 |
+ Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY
|
|
|
2733a1 |
+ Header SHA256 digest: OK
|
|
|
2733a1 |
+ Header SHA1 digest: OK
|
|
|
2733a1 |
+ Payload SHA256 digest: OK
|
|
|
2733a1 |
+ V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY
|
|
|
2733a1 |
+ MD5 digest: OK
|
|
|
2733a1 |
+1
|
|
|
2733a1 |
+/tmp/hello-2.0-1.x86_64-signed.rpm:
|
|
|
2733a1 |
+ Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK
|
|
|
2733a1 |
+ Header SHA256 digest: OK
|
|
|
2733a1 |
+ Header SHA1 digest: OK
|
|
|
2733a1 |
+ Payload SHA256 digest: OK
|
|
|
2733a1 |
+ V4 RSA/SHA256 Signature, key ID 1964c5fc: OK
|
|
|
2733a1 |
+ MD5 digest: OK
|
|
|
2733a1 |
+0
|
|
|
2733a1 |
+],
|
|
|
2733a1 |
+[])
|
|
|
2733a1 |
+AT_CLEANUP
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+# check that package in denylist is not transcoded
|
|
|
2733a1 |
+AT_SETUP([rpm2extents denylist])
|
|
|
2733a1 |
+AT_KEYWORDS([rpm2extents])
|
|
|
2733a1 |
+AT_CHECK([
|
|
|
2733a1 |
+export LIBREPO_TRANSCODE_RPMS_DENYLIST="vim,hello,cowsay"
|
|
|
2733a1 |
+runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | runroot_other cmp /data/RPMS/hello-2.0-1.x86_64.rpm -],
|
|
|
2733a1 |
+[0],
|
|
|
2733a1 |
+[],
|
|
|
2733a1 |
+[ignore])
|
|
|
2733a1 |
+AT_CLEANUP
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+AT_SETUP([rpm2extents install package])
|
|
|
2733a1 |
+AT_KEYWORDS([rpm2extents reflink])
|
|
|
2733a1 |
+AT_SKIP_IF([$REFLINK_DISABLED])
|
|
|
2733a1 |
+AT_CHECK([
|
|
|
2733a1 |
+RPMDB_INIT
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64.rpm 2> /dev/null
|
|
|
2733a1 |
+runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm
|
|
|
2733a1 |
+test -f ${RPMTEST}/usr/bin/hello
|
|
|
2733a1 |
+],
|
|
|
2733a1 |
+[0],
|
|
|
2733a1 |
+[],
|
|
|
2733a1 |
+[])
|
|
|
2733a1 |
+AT_CLEANUP
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+AT_SETUP([reflink ignores non-transcoded package])
|
|
|
2733a1 |
+AT_KEYWORDS([reflink])
|
|
|
2733a1 |
+AT_CHECK([
|
|
|
2733a1 |
+RPMDB_INIT
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $?
|
|
|
2733a1 |
+# Check that the file is properly installed in chroot
|
|
|
2733a1 |
+test -f ${RPMTEST}/usr/bin/hello
|
|
|
2733a1 |
+],
|
|
|
2733a1 |
+[0],
|
|
|
2733a1 |
+[],
|
|
|
2733a1 |
+[])
|
|
|
2733a1 |
+AT_CLEANUP
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+AT_SETUP([reflink hardlink package])
|
|
|
2733a1 |
+AT_KEYWORDS([reflink hardlink])
|
|
|
2733a1 |
+AT_SKIP_IF([$REFLINK_DISABLED])
|
|
|
2733a1 |
+AT_CHECK([
|
|
|
2733a1 |
+RPMDB_INIT
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+PKG=hlinktest-1.0-1.noarch.rpm
|
|
|
2733a1 |
+runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null
|
|
|
2733a1 |
+runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG}
|
|
|
2733a1 |
+],
|
|
|
2733a1 |
+[0],
|
|
|
2733a1 |
+[],
|
|
|
2733a1 |
+[])
|
|
|
2733a1 |
+AT_CLEANUP
|
|
|
2733a1 |
diff --git a/tests/rpmtests.at b/tests/rpmtests.at
|
|
|
2733a1 |
index d675452..3e6d528 100644
|
|
|
2733a1 |
--- a/tests/rpmtests.at
|
|
|
2733a1 |
+++ b/tests/rpmtests.at
|
|
|
2733a1 |
@@ -24,3 +24,4 @@ m4_include([rpmreplace.at])
|
|
|
2733a1 |
m4_include([rpmconfig.at])
|
|
|
2733a1 |
m4_include([rpmconfig2.at])
|
|
|
2733a1 |
m4_include([rpmconfig3.at])
|
|
|
2733a1 |
+m4_include([rpm2extents.at])
|
|
|
2733a1 |
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
|
|
|
2733a1 |
index f4fbefe..d369d20 100644
|
|
|
2733a1 |
--- a/tools/CMakeLists.txt
|
|
|
2733a1 |
+++ b/tools/CMakeLists.txt
|
|
|
2733a1 |
@@ -12,6 +12,7 @@ add_executable(rpmdeps rpmdeps.c)
|
|
|
2733a1 |
add_executable(rpmgraph rpmgraph.c)
|
|
|
2733a1 |
add_executable(rpmlua rpmlua.c)
|
|
|
2733a1 |
add_executable(rpmuncompress rpmuncompress.c)
|
|
|
2733a1 |
+add_executable(rpm2extents rpm2extents.c)
|
|
|
2733a1 |
|
|
|
2733a1 |
target_link_libraries(rpmsign PRIVATE librpmsign)
|
|
|
2733a1 |
target_link_libraries(rpmlua PRIVATE LUA::LUA)
|
|
|
2733a1 |
@@ -32,6 +33,7 @@ endif()
|
|
|
2733a1 |
|
|
|
2733a1 |
target_include_directories(rpmlua PRIVATE ${CMAKE_SOURCE_DIR}/rpmio)
|
|
|
2733a1 |
target_include_directories(rpmgraph PRIVATE ${CMAKE_SOURCE_DIR}/lib)
|
|
|
2733a1 |
+target_include_directories(rpm2extents PRIVATE ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/rpmio)
|
|
|
2733a1 |
|
|
|
2733a1 |
if (READLINE_FOUND)
|
|
|
2733a1 |
target_link_libraries(rpmspec PRIVATE PkgConfig::READLINE)
|
|
|
2733a1 |
@@ -62,5 +64,4 @@ install(TARGETS
|
|
|
2733a1 |
rpm rpmdb rpmkeys rpm2cpio rpmsign rpmbuild rpmspec
|
|
|
2733a1 |
rpmlua rpmgraph
|
|
|
2733a1 |
)
|
|
|
2733a1 |
-install(TARGETS rpmdeps rpmuncompress DESTINATION ${RPM_CONFIGDIR})
|
|
|
2733a1 |
-
|
|
|
2733a1 |
+install(TARGETS rpmdeps rpmuncompress rpm2extents DESTINATION ${RPM_CONFIGDIR})
|
|
|
2733a1 |
diff --git a/tools/rpm2extents.c b/tools/rpm2extents.c
|
|
|
2733a1 |
new file mode 100644
|
|
|
2733a1 |
index 0000000..98124c2
|
|
|
2733a1 |
--- /dev/null
|
|
|
2733a1 |
+++ b/tools/rpm2extents.c
|
|
|
2733a1 |
@@ -0,0 +1,707 @@
|
|
|
2733a1 |
+/* rpm2extents: convert payload to inline extents */
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include "system.h"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include <rpm/rpmcli.h>
|
|
|
2733a1 |
+#include <rpm/rpmlib.h> /* rpmReadPackageFile .. */
|
|
|
2733a1 |
+#include <rpm/rpmlog.h>
|
|
|
2733a1 |
+#include <rpm/rpmfi.h>
|
|
|
2733a1 |
+#include <rpm/rpmtag.h>
|
|
|
2733a1 |
+#include <rpm/rpmio.h>
|
|
|
2733a1 |
+#include <rpm/rpmpgp.h>
|
|
|
2733a1 |
+#include <rpm/rpmts.h>
|
|
|
2733a1 |
+#include <rpm/rpmextents_internal.h>
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include "rpmlead.h"
|
|
|
2733a1 |
+#include "signature.h"
|
|
|
2733a1 |
+#include "header_internal.h"
|
|
|
2733a1 |
+#include "rpmio_internal.h"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include <unistd.h>
|
|
|
2733a1 |
+#include <sys/types.h>
|
|
|
2733a1 |
+#include <sys/wait.h>
|
|
|
2733a1 |
+#include <signal.h>
|
|
|
2733a1 |
+#include <errno.h>
|
|
|
2733a1 |
+#include <string.h>
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+#include "debug.h"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/* hash of void * (pointers) to file digests to offsets within output.
|
|
|
2733a1 |
+ * The length of the key depends on what the FILEDIGESTALGO is.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+#undef HASHTYPE
|
|
|
2733a1 |
+#undef HTKEYTYPE
|
|
|
2733a1 |
+#undef HTDATATYPE
|
|
|
2733a1 |
+#define HASHTYPE digestSet
|
|
|
2733a1 |
+#define HTKEYTYPE const unsigned char *
|
|
|
2733a1 |
+#include "rpmhash.H"
|
|
|
2733a1 |
+#include "rpmhash.C"
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+struct digestoffset {
|
|
|
2733a1 |
+ const unsigned char * digest;
|
|
|
2733a1 |
+ rpm_loff_t pos;
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ return (unit - (pos % unit)) % unit;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static struct poptOption optionsTable[] = {
|
|
|
2733a1 |
+ { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
|
|
|
2733a1 |
+ N_("Common options for all rpm modes and executables:"), NULL },
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ POPT_AUTOALIAS
|
|
|
2733a1 |
+ POPT_AUTOHELP
|
|
|
2733a1 |
+ POPT_TABLEEND
|
|
|
2733a1 |
+};
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static void FDDigestInit(FD_t fdi, uint8_t algos[], uint32_t algos_len){
|
|
|
2733a1 |
+ int algo;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ for (algo = 0; algo < algos_len; algo++) {
|
|
|
2733a1 |
+ fdInitDigest(fdi, algos[algo], 0);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static int FDWriteDigests(
|
|
|
2733a1 |
+ FD_t fdi,
|
|
|
2733a1 |
+ FD_t fdo,
|
|
|
2733a1 |
+ uint8_t algos[],
|
|
|
2733a1 |
+ uint32_t algos_len)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ const char *filedigest, *algo_name;
|
|
|
2733a1 |
+ size_t filedigest_len, len;
|
|
|
2733a1 |
+ uint32_t algo_name_len, algo_digest_len;
|
|
|
2733a1 |
+ int algo;
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_FAIL;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ ssize_t fdilength = fdOp(fdi, FDSTAT_READ)->bytes;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ len = sizeof(fdilength);
|
|
|
2733a1 |
+ if (Fwrite(&fdilength, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write input length %zd: %d, %s\n"),
|
|
|
2733a1 |
+ fdilength, errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ len = sizeof(algos_len);
|
|
|
2733a1 |
+ if (Fwrite(&algos_len, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ algo_digest_len = (uint32_t)filedigest_len;
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write number of digests: %d, %s\n"),
|
|
|
2733a1 |
+ errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ for (algo = 0; algo < algos_len; algo++) {
|
|
|
2733a1 |
+ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]);
|
|
|
2733a1 |
+ algo_name_len = (uint32_t)strlen(algo_name);
|
|
|
2733a1 |
+ algo_digest_len = (uint32_t)filedigest_len;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ len = sizeof(algo_name_len);
|
|
|
2733a1 |
+ if (Fwrite(&algo_name_len, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Unable to write digest algo name length: %d, %s\n"),
|
|
|
2733a1 |
+ errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ len = sizeof(algo_digest_len);
|
|
|
2733a1 |
+ if (Fwrite(&algo_digest_len, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Unable to write number of bytes for digest: %d, %s\n"),
|
|
|
2733a1 |
+ errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (Fwrite(algo_name, algo_name_len, 1, fdo) != algo_name_len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write digest algo name: %d, %s\n"),
|
|
|
2733a1 |
+ errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (Fwrite(filedigest, algo_digest_len, 1, fdo ) != algo_digest_len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Unable to write digest value %u, %zu: %d, %s\n"),
|
|
|
2733a1 |
+ algo_digest_len, filedigest_len,
|
|
|
2733a1 |
+ errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+exit:
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+/**
|
|
|
2733a1 |
+ * Check if package is in deny list.
|
|
|
2733a1 |
+ * @param package_name package name
|
|
|
2733a1 |
+ * @return true if package is in deny list
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+static inline int isInDenyList(char *package_name)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ int is_in_deny_list = 0;
|
|
|
2733a1 |
+ if (package_name) {
|
|
|
2733a1 |
+ char *e_denylist = getenv("LIBREPO_TRANSCODE_RPMS_DENYLIST");
|
|
|
2733a1 |
+ char *denytlist_item = strtok(e_denylist, ",");
|
|
|
2733a1 |
+ while (denytlist_item) {
|
|
|
2733a1 |
+ if (strstr(package_name, denytlist_item)) {
|
|
|
2733a1 |
+ is_in_deny_list = 1;
|
|
|
2733a1 |
+ break;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ denytlist_item = strtok(NULL, ",");
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return is_in_deny_list;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) {
|
|
|
2733a1 |
+ size_t len;
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_FAIL;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if(rpmvsrc){
|
|
|
2733a1 |
+ rpmlog(RPMLOG_WARNING,
|
|
|
2733a1 |
+ _("Error verifying package signatures:\n%s\n"), msg);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ len = sizeof(rpmvsrc);
|
|
|
2733a1 |
+ if (Fwrite(&rpmvsrc, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Unable to write signature verification RC code %d: %d, %s\n"),
|
|
|
2733a1 |
+ rpmvsrc, errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ size_t content_len = msg ? strlen(msg) : 0;
|
|
|
2733a1 |
+ len = sizeof(content_len);
|
|
|
2733a1 |
+ if (Fwrite(&content_len, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Unable to write signature verification output length %zd: %d, %s\n"),
|
|
|
2733a1 |
+ content_len, errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (Fwrite(msg, content_len, 1, fdo) != content_len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Unable to write signature verification output %s: %d, %s\n"),
|
|
|
2733a1 |
+ msg, errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+exit:
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC validator(FD_t fdi, FD_t digesto, FD_t sigo,
|
|
|
2733a1 |
+ uint8_t algos[],
|
|
|
2733a1 |
+ uint32_t algos_len){
|
|
|
2733a1 |
+ int rpmvsrc;
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ char *msg = NULL;
|
|
|
2733a1 |
+ rpmts ts = rpmtsCreate();
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rpmtsSetRootDir(ts, rpmcliRootDir);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ FDDigestInit(fdi, algos, algos_len);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rpmvsrc = rpmcliVerifySignaturesFD(ts, fdi, &msg;;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ // Write result of digest computation
|
|
|
2733a1 |
+ if(FDWriteDigests(fdi, digesto, algos, algos_len) != RPMRC_OK) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Failed to write digests: %d, %s\n"),
|
|
|
2733a1 |
+ errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ // Write result of signature validation.
|
|
|
2733a1 |
+ if(FDWriteSignaturesValidation(sigo, rpmvsrc, msg)) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Failed to write signature verification result: %d, %s\n"),
|
|
|
2733a1 |
+ errno, strerror(errno));
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+exit:
|
|
|
2733a1 |
+ if(msg) {
|
|
|
2733a1 |
+ free(msg);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpmtsFree(ts);
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static void sanitizeSignatureHeader(Header * sigh)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ struct rpmtd_s td;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* This is inspired by the code in unloadImmutableRegion. See https://github.com/rpm-software-management/rpm/pull/1330 */
|
|
|
2733a1 |
+ if (!headerGet(*sigh, RPMTAG_HEADERSIGNATURES, &td, HEADERGET_DEFAULT)) {
|
|
|
2733a1 |
+ /* Signature header corrupt/missing */
|
|
|
2733a1 |
+ rpmlog(RPMLOG_WARNING, _("Error verifying signature header\n"));
|
|
|
2733a1 |
+ rpmtdFreeData(&td);
|
|
|
2733a1 |
+ Header nh = headerCopy(*sigh);
|
|
|
2733a1 |
+ headerFree(*sigh);
|
|
|
2733a1 |
+ *sigh = headerLink(nh);
|
|
|
2733a1 |
+ headerFree(nh);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ rpmtdFreeData(&td);
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ uint32_t diglen;
|
|
|
2733a1 |
+ /* GNU C extension: can use diglen from outer context */
|
|
|
2733a1 |
+ int digestSetCmp(const unsigned char * a, const unsigned char * b) {
|
|
|
2733a1 |
+ return memcmp(a, b, diglen);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ unsigned int digestSetHash(const unsigned char * digest) {
|
|
|
2733a1 |
+ /* assumes sizeof(unsigned int) < diglen */
|
|
|
2733a1 |
+ return *(unsigned int *)digest;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ int digestoffsetCmp(const void * a, const void * b) {
|
|
|
2733a1 |
+ return digestSetCmp(
|
|
|
2733a1 |
+ ((struct digestoffset *)a)->digest,
|
|
|
2733a1 |
+ ((struct digestoffset *)b)->digest
|
|
|
2733a1 |
+ );
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ FD_t fdo;
|
|
|
2733a1 |
+ FD_t gzdi;
|
|
|
2733a1 |
+ Header h, sigh;
|
|
|
2733a1 |
+ long fundamental_block_size = sysconf(_SC_PAGESIZE);
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_OK;
|
|
|
2733a1 |
+ rpm_mode_t mode;
|
|
|
2733a1 |
+ char *rpmio_flags = NULL, *zeros;
|
|
|
2733a1 |
+ const unsigned char *digest;
|
|
|
2733a1 |
+ rpm_loff_t pos, size, pad, digest_pos, validation_pos, digest_table_pos;
|
|
|
2733a1 |
+ uint32_t offset_ix = 0;
|
|
|
2733a1 |
+ size_t len;
|
|
|
2733a1 |
+ int next = 0;
|
|
|
2733a1 |
+ struct rpmlead_s l;
|
|
|
2733a1 |
+ rpmfiles files = NULL;
|
|
|
2733a1 |
+ rpmfi fi = NULL;
|
|
|
2733a1 |
+ char *msg = NULL;
|
|
|
2733a1 |
+ struct digestoffset *offsets = NULL;
|
|
|
2733a1 |
+ digestSet ds = NULL;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ fdo = fdDup(STDOUT_FILENO);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rc = rpmLeadReadAndReturn(fdi, &msg, &l);
|
|
|
2733a1 |
+ if (rc != RPMRC_OK)
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* Skip conversion if package is in deny list */
|
|
|
2733a1 |
+ if (isInDenyList(l.name)) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_WARNING, _("package %s is in deny list: conversion skipped\n"), l.name);
|
|
|
2733a1 |
+ if (rpmLeadWrite(fdo, l)) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),
|
|
|
2733a1 |
+ Fstrerror(fdo));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ ssize_t fdilength = ufdCopy(fdi, fdo);
|
|
|
2733a1 |
+ if (fdilength == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("process_package cat failed\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ if (rpmReadPackageRaw(fdi, &sigh, &h)) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Error reading package\n"));
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ sanitizeSignatureHeader(&sigh;;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (rpmLeadWriteFromHeader(fdo, h)) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),
|
|
|
2733a1 |
+ Fstrerror(fdo));
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (rpmWriteSignature(fdo, sigh)) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"),
|
|
|
2733a1 |
+ Fstrerror(fdo));
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"),
|
|
|
2733a1 |
+ Fstrerror(fdo));
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* Retrieve payload size and compression type. */
|
|
|
2733a1 |
+ {
|
|
|
2733a1 |
+ const char *compr =
|
|
|
2733a1 |
+ headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
|
|
|
2733a1 |
+ rpmio_flags =
|
|
|
2733a1 |
+ rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */
|
|
|
2733a1 |
+ free(rpmio_flags);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (gzdi == NULL) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"),
|
|
|
2733a1 |
+ Fstrerror(gzdi));
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
|
|
|
2733a1 |
+ fi = rpmfiNewArchiveReader(gzdi, files,
|
|
|
2733a1 |
+ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* this is encoded in the file format, so needs to be fixed size (for
|
|
|
2733a1 |
+ * now?)
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ diglen = (uint32_t) rpmDigestLength(rpmfiDigestAlgo(fi));
|
|
|
2733a1 |
+ ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, NULL);
|
|
|
2733a1 |
+ offsets = xcalloc(rpmfiFC(fi), sizeof(*offsets));
|
|
|
2733a1 |
+ pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* main headers are aligned to 8 byte boundry */
|
|
|
2733a1 |
+ pos += pad_to(pos, 8);
|
|
|
2733a1 |
+ pos += headerSizeof(h, HEADER_MAGIC_YES);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ zeros = xcalloc(fundamental_block_size, 1);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ while (next >= 0) {
|
|
|
2733a1 |
+ next = rpmfiNext(fi);
|
|
|
2733a1 |
+ if (next == RPMERR_ITER_END) {
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+ break;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ mode = rpmfiFMode(fi);
|
|
|
2733a1 |
+ if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) {
|
|
|
2733a1 |
+ /* not a regular file, or the archive doesn't contain any content
|
|
|
2733a1 |
+ * for this entry.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+ continue;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ digest = rpmfiFDigest(fi, NULL, NULL);
|
|
|
2733a1 |
+ if (digestSetGetEntry(ds, digest, NULL)) {
|
|
|
2733a1 |
+ /* This specific digest has already been included, so skip it. */
|
|
|
2733a1 |
+ continue;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ pad = pad_to(pos, fundamental_block_size);
|
|
|
2733a1 |
+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write padding\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ /* round up to next fundamental_block_size */
|
|
|
2733a1 |
+ pos += pad;
|
|
|
2733a1 |
+ digestSetAddEntry(ds, digest);
|
|
|
2733a1 |
+ offsets[offset_ix].digest = digest;
|
|
|
2733a1 |
+ offsets[offset_ix].pos = pos;
|
|
|
2733a1 |
+ offset_ix++;
|
|
|
2733a1 |
+ size = rpmfiFSize(fi);
|
|
|
2733a1 |
+ rc = rpmfiArchiveReadToFile(fi, fdo, 0);
|
|
|
2733a1 |
+ if (rc != RPMRC_OK) {
|
|
|
2733a1 |
+ char *errstr = rpmfileStrerror(rc);
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("rpmfiArchiveReadToFile failed while extracting "
|
|
|
2733a1 |
+ "\"%s\" with RC %d: %s\n"),
|
|
|
2733a1 |
+ rpmfiFN(fi), rc, errstr);
|
|
|
2733a1 |
+ free(errstr);
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ pos += size;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ Fclose(gzdi); /* XXX gzdi == fdi */
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ qsort(offsets, (size_t) offset_ix, sizeof(struct digestoffset),
|
|
|
2733a1 |
+ digestoffsetCmp);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ validation_pos = pos;
|
|
|
2733a1 |
+ ssize_t validation_len = ufdCopy(validationi, fdo);
|
|
|
2733a1 |
+ if (validation_len == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ digest_table_pos = validation_pos + validation_len;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ len = sizeof(offset_ix);
|
|
|
2733a1 |
+ if (Fwrite(&offset_ix, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write length of table\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ len = sizeof(diglen);
|
|
|
2733a1 |
+ if (Fwrite(&diglen, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ len = sizeof(rpm_loff_t);
|
|
|
2733a1 |
+ for (int x = 0; x < offset_ix; x++) {
|
|
|
2733a1 |
+ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write digest\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write offset\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ digest_pos =
|
|
|
2733a1 |
+ (digest_table_pos + sizeof(offset_ix) + sizeof(diglen) +
|
|
|
2733a1 |
+ offset_ix * (diglen + sizeof(rpm_loff_t))
|
|
|
2733a1 |
+ );
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ ssize_t digest_len = ufdCopy(digestori, fdo);
|
|
|
2733a1 |
+ if (digest_len == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ /* add more padding so the last file can be cloned. It doesn't matter that
|
|
|
2733a1 |
+ * the table and validation etc are in this space. In fact, it's pretty
|
|
|
2733a1 |
+ * efficient if it is.
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ pad =
|
|
|
2733a1 |
+ pad_to((validation_pos + validation_len +
|
|
|
2733a1 |
+ 2 * sizeof(rpm_loff_t) + sizeof(uint64_t)),
|
|
|
2733a1 |
+ fundamental_block_size);
|
|
|
2733a1 |
+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write final padding\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ zeros = _free(zeros);
|
|
|
2733a1 |
+ struct extents_footer_t footer = {.offsets =
|
|
|
2733a1 |
+ { validation_pos, digest_table_pos, digest_pos },.magic =
|
|
|
2733a1 |
+ EXTENTS_MAGIC };
|
|
|
2733a1 |
+ len = sizeof(footer);
|
|
|
2733a1 |
+ if (Fwrite(&footer, len, 1, fdo) != len) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Unable to write footer\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ goto exit;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ exit:
|
|
|
2733a1 |
+ rpmfilesFree(files);
|
|
|
2733a1 |
+ rpmfiFree(fi);
|
|
|
2733a1 |
+ headerFree(h);
|
|
|
2733a1 |
+ headerFree(sigh);
|
|
|
2733a1 |
+ free(offsets);
|
|
|
2733a1 |
+ Fclose(fdo);
|
|
|
2733a1 |
+ digestSetFree(ds);
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static off_t ufdTee(FD_t sfd, FD_t *fds, int len)
|
|
|
2733a1 |
+{
|
|
|
2733a1 |
+ char buf[BUFSIZ];
|
|
|
2733a1 |
+ ssize_t rdbytes, wrbytes;
|
|
|
2733a1 |
+ off_t total = 0;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ while (1) {
|
|
|
2733a1 |
+ rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (rdbytes > 0) {
|
|
|
2733a1 |
+ for(int i=0; i < len; i++) {
|
|
|
2733a1 |
+ wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, fds[i]);
|
|
|
2733a1 |
+ if (wrbytes != rdbytes) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Error wriing to FD %d: %s\n"),
|
|
|
2733a1 |
+ i, Fstrerror(fds[i]));
|
|
|
2733a1 |
+ total = -1;
|
|
|
2733a1 |
+ break;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ if(total == -1){
|
|
|
2733a1 |
+ break;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ total += wrbytes;
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ if (rdbytes < 0)
|
|
|
2733a1 |
+ total = -1;
|
|
|
2733a1 |
+ break;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return total;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) {
|
|
|
2733a1 |
+ rpmRC rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ off_t offt = -1;
|
|
|
2733a1 |
+ // tee-ed stdin
|
|
|
2733a1 |
+ int processorpipefd[2];
|
|
|
2733a1 |
+ int validatorpipefd[2];
|
|
|
2733a1 |
+ // metadata
|
|
|
2733a1 |
+ int meta_digestpipefd[2];
|
|
|
2733a1 |
+ int meta_rpmsignpipefd[2];
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ pid_t cpids[2], w;
|
|
|
2733a1 |
+ int wstatus;
|
|
|
2733a1 |
+ FD_t fds[2];
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (pipe(processorpipefd) == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Processor pipe failure\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (pipe(validatorpipefd) == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Validator pipe failure\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (pipe(meta_digestpipefd) == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Meta digest pipe failure\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (pipe(meta_rpmsignpipefd) == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Meta rpm signature pipe failure\n"));
|
|
|
2733a1 |
+ return RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ cpids[0] = fork();
|
|
|
2733a1 |
+ if (cpids[0] == 0) {
|
|
|
2733a1 |
+ /* child: validator */
|
|
|
2733a1 |
+ close(processorpipefd[0]);
|
|
|
2733a1 |
+ close(processorpipefd[1]);
|
|
|
2733a1 |
+ close(validatorpipefd[1]);
|
|
|
2733a1 |
+ close(meta_digestpipefd[0]);
|
|
|
2733a1 |
+ close(meta_rpmsignpipefd[0]);
|
|
|
2733a1 |
+ FD_t fdi = fdDup(validatorpipefd[0]);
|
|
|
2733a1 |
+ FD_t digesto = fdDup(meta_digestpipefd[1]);
|
|
|
2733a1 |
+ FD_t sigo = fdDup(meta_rpmsignpipefd[1]);
|
|
|
2733a1 |
+ close(meta_digestpipefd[1]);
|
|
|
2733a1 |
+ close(meta_rpmsignpipefd[1]);
|
|
|
2733a1 |
+ rc = validator(fdi, digesto, sigo, algos, algos_len);
|
|
|
2733a1 |
+ if(rc != RPMRC_OK) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Validator failed with RC %d\n"), rc);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ Fclose(fdi);
|
|
|
2733a1 |
+ Fclose(digesto);
|
|
|
2733a1 |
+ Fclose(sigo);
|
|
|
2733a1 |
+ if (rc != RPMRC_OK) {
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ exit(EXIT_SUCCESS);
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ /* parent: main program */
|
|
|
2733a1 |
+ cpids[1] = fork();
|
|
|
2733a1 |
+ if (cpids[1] == 0) {
|
|
|
2733a1 |
+ /* child: process_package */
|
|
|
2733a1 |
+ close(validatorpipefd[0]);
|
|
|
2733a1 |
+ close(validatorpipefd[1]);
|
|
|
2733a1 |
+ close(processorpipefd[1]);
|
|
|
2733a1 |
+ close(meta_digestpipefd[1]);
|
|
|
2733a1 |
+ close(meta_rpmsignpipefd[1]);
|
|
|
2733a1 |
+ FD_t fdi = fdDup(processorpipefd[0]);
|
|
|
2733a1 |
+ close(processorpipefd[0]);
|
|
|
2733a1 |
+ FD_t sigi = fdDup(meta_rpmsignpipefd[0]);
|
|
|
2733a1 |
+ close(meta_rpmsignpipefd[0]);
|
|
|
2733a1 |
+ FD_t digestori = fdDup(meta_digestpipefd[0]);
|
|
|
2733a1 |
+ close(meta_digestpipefd[0]);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rc = process_package(fdi, digestori, sigi);
|
|
|
2733a1 |
+ if(rc != RPMRC_OK) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Package processor failed: %d\n"), rc);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ Fclose(digestori);
|
|
|
2733a1 |
+ Fclose(sigi);
|
|
|
2733a1 |
+ /* fdi is normally closed through the stacked file gzdi in the
|
|
|
2733a1 |
+ * function
|
|
|
2733a1 |
+ */
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (rc != RPMRC_OK) {
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ exit(EXIT_SUCCESS);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ } else {
|
|
|
2733a1 |
+ /* Actual parent. Read from fdi and write to both processes */
|
|
|
2733a1 |
+ close(processorpipefd[0]);
|
|
|
2733a1 |
+ close(validatorpipefd[0]);
|
|
|
2733a1 |
+ fds[0] = fdDup(processorpipefd[1]);
|
|
|
2733a1 |
+ fds[1] = fdDup(validatorpipefd[1]);
|
|
|
2733a1 |
+ close(validatorpipefd[1]);
|
|
|
2733a1 |
+ close(processorpipefd[1]);
|
|
|
2733a1 |
+ close(meta_digestpipefd[0]);
|
|
|
2733a1 |
+ close(meta_digestpipefd[1]);
|
|
|
2733a1 |
+ close(meta_rpmsignpipefd[0]);
|
|
|
2733a1 |
+ close(meta_rpmsignpipefd[1]);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ rc = RPMRC_OK;
|
|
|
2733a1 |
+ offt = ufdTee(fdi, fds, 2);
|
|
|
2733a1 |
+ if(offt == -1){
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("Failed to tee RPM\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ Fclose(fds[0]);
|
|
|
2733a1 |
+ Fclose(fds[1]);
|
|
|
2733a1 |
+ w = waitpid(cpids[0], &wstatus, 0);
|
|
|
2733a1 |
+ if (w == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("waitpid cpids[0] failed\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ w = waitpid(cpids[1], &wstatus, 0);
|
|
|
2733a1 |
+ if (w == -1) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR, _("waitpid cpids[1] failed\n"));
|
|
|
2733a1 |
+ rc = RPMRC_FAIL;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ return rc;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+int main(int argc, char *argv[]) {
|
|
|
2733a1 |
+ rpmRC rc;
|
|
|
2733a1 |
+ poptContext optCon = NULL;
|
|
|
2733a1 |
+ const char **args = NULL;
|
|
|
2733a1 |
+ int nb_algos = 0;
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ xsetprogname(argv[0]); /* Portability call -- see system.h */
|
|
|
2733a1 |
+ rpmReadConfigFiles(NULL, NULL);
|
|
|
2733a1 |
+ optCon = rpmcliInit(argc, argv, optionsTable);
|
|
|
2733a1 |
+ poptSetOtherOptionHelp(optCon, "[OPTIONS]* <DIGESTALGO>");
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ if (poptPeekArg(optCon) == NULL) {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n"));
|
|
|
2733a1 |
+ poptPrintUsage(optCon, stderr, 0);
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ args = poptGetArgs(optCon);
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ for (nb_algos=0; args[nb_algos]; nb_algos++);
|
|
|
2733a1 |
+ uint8_t algos[nb_algos];
|
|
|
2733a1 |
+ for (int x = 0; x < nb_algos; x++) {
|
|
|
2733a1 |
+ if (pgpStringVal(PGPVAL_HASHALGO, args[x], &algos[x]) != 0)
|
|
|
2733a1 |
+ {
|
|
|
2733a1 |
+ rpmlog(RPMLOG_ERR,
|
|
|
2733a1 |
+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"),
|
|
|
2733a1 |
+ args[x]);
|
|
|
2733a1 |
+ exit(EXIT_FAILURE);
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+
|
|
|
2733a1 |
+ FD_t fdi = fdDup(STDIN_FILENO);
|
|
|
2733a1 |
+ rc = teeRpm(fdi, algos, nb_algos);
|
|
|
2733a1 |
+ Fclose(fdi);
|
|
|
2733a1 |
+ if (rc != RPMRC_OK) {
|
|
|
2733a1 |
+ /* translate rpmRC into generic failure return code. */
|
|
|
2733a1 |
+ return EXIT_FAILURE;
|
|
|
2733a1 |
+ }
|
|
|
2733a1 |
+ return EXIT_SUCCESS;
|
|
|
2733a1 |
+}
|
|
|
2733a1 |
--
|
|
|
2733a1 |
2.47.1
|
|
|
2733a1 |
|