|
|
b3c12f |
From 82b454d2ff43b39e1a3b38fded0c2e5caffcd336 Mon Sep 17 00:00:00 2001
|
|
|
b3c12f |
From: Matthew Almond <malmond@fb.com>
|
|
|
b3c12f |
Date: Fri, 8 Nov 2019 09:29:43 -0800
|
|
|
b3c12f |
Subject: [PATCH 1/4] RPM with Copy on Write
|
|
|
b3c12f |
|
|
|
b3c12f |
This is part of https://fedoraproject.org/wiki/Changes/RPMCoW
|
|
|
b3c12f |
|
|
|
b3c12f |
The majority of changes are in two new programs:
|
|
|
b3c12f |
|
|
|
b3c12f |
= rpm2extents
|
|
|
b3c12f |
|
|
|
b3c12f |
Modeled as a 'stream processor'. It reads a regular .rpm file on stdin,
|
|
|
b3c12f |
and produces a modified .rpm file on stdout. The lead, signature and
|
|
|
b3c12f |
headers are preserved 1:1 to allow all the normal metadata inspection,
|
|
|
b3c12f |
signature verification to work as expected. Only the 'payload' is
|
|
|
b3c12f |
modified.
|
|
|
b3c12f |
|
|
|
b3c12f |
The primary motivation for this tool is to re-organize the payload as a
|
|
|
b3c12f |
sequence of raw file extents (hence the name). The files are organized
|
|
|
b3c12f |
by their digest identity instead of path/filename. If any digest is
|
|
|
b3c12f |
repeated, then the file is skipped/de-duped. Only regular files are
|
|
|
b3c12f |
represented. All other entries like directories, symlinks, devices are
|
|
|
b3c12f |
fully described in the headers and are omitted.
|
|
|
b3c12f |
|
|
|
b3c12f |
The files are padded so they start on `sysconf(_SC_PAGESIZE)` boundries
|
|
|
b3c12f |
to permit 'reflink' syscalls to work in the `reflink` plugin.
|
|
|
b3c12f |
|
|
|
b3c12f |
At the end of the file is a footer with 3 sections:
|
|
|
b3c12f |
|
|
|
b3c12f |
1. List of calculated digests of the input stream. This is used in
|
|
|
b3c12f |
`librepo` because the file *written* is a derivative, and not the
|
|
|
b3c12f |
same as the repo metadata describes. `rpm2extents` takes one or more
|
|
|
b3c12f |
positional arguments that described which digest algorithms are
|
|
|
b3c12f |
desired. This is often just `SHA256`. This program is only measuring
|
|
|
b3c12f |
and recording the digest - it does not express an opinion on whether
|
|
|
b3c12f |
the file is correct. Due to the API on most compression libraries
|
|
|
b3c12f |
directly reading the source file, the whole file digest is measured
|
|
|
b3c12f |
using a subprocess and pipes. I don't love it, but it works.
|
|
|
b3c12f |
2. Sorted List of file content digests + offset pairs. This is used in
|
|
|
b3c12f |
the plugin with a trivial binary search to locate the start of file
|
|
|
b3c12f |
content. The size is not needed because it's part of normal headers.
|
|
|
b3c12f |
3. (offset of 1., offset of 2., 8 byte MAGIC value) triple
|
|
|
b3c12f |
|
|
|
b3c12f |
= reflink plugin
|
|
|
b3c12f |
|
|
|
b3c12f |
Looks for the 8 byte magic value at the end of the rpm file. If present
|
|
|
b3c12f |
it alters the `RPMTAG_PAYLOADFORMAT` in memory to `clon`, and reads in
|
|
|
b3c12f |
the digest-> offset table.
|
|
|
b3c12f |
|
|
|
b3c12f |
`rpmPackageFilesInstall()` in `fsm.c` is
|
|
|
b3c12f |
modified to alter the enumeration strategy from
|
|
|
b3c12f |
`rpmfiNewArchiveReader()` to `rpmfilesIter()` if not `cpio`. This is
|
|
|
b3c12f |
needed because there is no cpio to enumerate. In the same function, if
|
|
|
b3c12f |
`rpmpluginsCallFsmFilePre()` returns `RPMRC_PLUGIN_CONTENTS` then
|
|
|
b3c12f |
`fsmMkfile()` is skipped as it is assumed the plugin did the work.
|
|
|
b3c12f |
|
|
|
b3c12f |
The majority of the work is in `reflink_fsm_file_pre()` - the per file
|
|
|
b3c12f |
hook for RPM plugins. If the file enumerated in
|
|
|
b3c12f |
`rpmPackageFilesInstall()` is a regular file, this function will look up
|
|
|
b3c12f |
the offset in the digest->offset table and will try to reflink it, then
|
|
|
b3c12f |
fall back to a regular copy. If reflinking does work: we will have
|
|
|
b3c12f |
reflinked a whole number of pages, so we truncate the file to the
|
|
|
b3c12f |
expected size. Therefore installing most files does involve two writes:
|
|
|
b3c12f |
the reflink of the full size, then a fork/copy on write for the last
|
|
|
b3c12f |
page worth.
|
|
|
b3c12f |
|
|
|
b3c12f |
If the file passed to `reflink_fsm_file_pre()` is anything other than a
|
|
|
b3c12f |
regular file, it return `RPMRC_OK` so the normal mechanics of
|
|
|
b3c12f |
`rpmPackageFilesInstall()` are used. That handles directories, symlinks
|
|
|
b3c12f |
and other non file types.
|
|
|
b3c12f |
|
|
|
b3c12f |
= New API for internal use
|
|
|
b3c12f |
|
|
|
b3c12f |
1. `rpmReadPackageRaw()` is used within `rpm2extents` to read all the
|
|
|
b3c12f |
headers without trying to validate signatures. This eliminates the
|
|
|
b3c12f |
runtime dependency on rpmdb.
|
|
|
b3c12f |
2. `rpmteFd()` exposes the Fd behind the rpmte, so plugins can interact
|
|
|
b3c12f |
with the rpm itself.
|
|
|
b3c12f |
3. `RPMRC_PLUGIN_CONTENTS` in `rpmRC_e` for use in
|
|
|
b3c12f |
`rpmpluginsCallFsmFilePre()` specifically.
|
|
|
b3c12f |
4. `pgpStringVal()` is used to help parse the command line in
|
|
|
b3c12f |
`rpm2extents` - the positional arguments are strings, and this
|
|
|
b3c12f |
converts the values back to the values in the table.
|
|
|
b3c12f |
|
|
|
b3c12f |
Nothing has been removed, and none of the changes are intended to be
|
|
|
b3c12f |
used externally, so I don't think a soname bump is warranted here.
|
|
|
b3c12f |
---
|
|
|
b3c12f |
Makefile.am | 6 +-
|
|
|
b3c12f |
lib/depends.c | 2 +
|
|
|
b3c12f |
lib/fsm.c | 50 ++++-
|
|
|
b3c12f |
lib/package.c | 40 ++++
|
|
|
b3c12f |
lib/rpmlib.h | 9 +
|
|
|
b3c12f |
lib/rpmplugins.c | 21 +-
|
|
|
b3c12f |
lib/rpmte.c | 5 +
|
|
|
b3c12f |
lib/rpmte.h | 2 +
|
|
|
b3c12f |
lib/rpmtypes.h | 3 +-
|
|
|
b3c12f |
macros.in | 1 +
|
|
|
b3c12f |
plugins/Makefile.am | 4 +
|
|
|
b3c12f |
plugins/reflink.c | 340 +++++++++++++++++++++++++++++
|
|
|
b3c12f |
rpm2extents.c | 519 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
b3c12f |
rpmio/rpmpgp.c | 10 +
|
|
|
b3c12f |
rpmio/rpmpgp.h | 9 +
|
|
|
b3c12f |
15 files changed, 1006 insertions(+), 15 deletions(-)
|
|
|
b3c12f |
create mode 100644 plugins/reflink.c
|
|
|
b3c12f |
create mode 100644 rpm2extents.c
|
|
|
b3c12f |
|
|
|
b3c12f |
diff --git a/Makefile.am b/Makefile.am
|
|
|
b3c12f |
index aca2f8996..17c1e0e8a 100644
|
|
|
b3c12f |
--- a/Makefile.am
|
|
|
b3c12f |
+++ b/Makefile.am
|
|
|
b3c12f |
@@ -105,7 +105,7 @@ pkginclude_HEADERS += build/rpmfc.h
|
|
|
b3c12f |
pkginclude_HEADERS += build/rpmspec.h
|
|
|
b3c12f |
|
|
|
b3c12f |
|
|
|
b3c12f |
-bin_PROGRAMS = rpm rpm2cpio rpmbuild rpmdb rpmkeys rpmsign rpmspec
|
|
|
b3c12f |
+bin_PROGRAMS = rpm rpm2cpio rpmbuild rpmdb rpmkeys rpmsign rpmspec rpm2extents
|
|
|
b3c12f |
if WITH_ARCHIVE
|
|
|
b3c12f |
bin_PROGRAMS += rpm2archive
|
|
|
b3c12f |
endif
|
|
|
b3c12f |
@@ -159,6 +159,10 @@ rpm2cpio_SOURCES = rpm2cpio.c debug.h system.h
|
|
|
b3c12f |
rpm2cpio_LDADD = lib/librpm.la rpmio/librpmio.la
|
|
|
b3c12f |
rpm2cpio_LDADD += @WITH_POPT_LIB@
|
|
|
b3c12f |
|
|
|
b3c12f |
+rpm2extents_SOURCES = rpm2extents.c debug.h system.h
|
|
|
b3c12f |
+rpm2extents_LDADD = lib/librpm.la rpmio/librpmio.la
|
|
|
b3c12f |
+rpm2extents_LDADD += @WITH_POPT_LIB@
|
|
|
b3c12f |
+
|
|
|
b3c12f |
rpm2archive_SOURCES = rpm2archive.c debug.h system.h
|
|
|
b3c12f |
rpm2archive_LDADD = lib/librpm.la rpmio/librpmio.la
|
|
|
b3c12f |
rpm2archive_LDADD += @WITH_POPT_LIB@ @WITH_ARCHIVE_LIB@
|
|
|
b3c12f |
diff --git a/lib/depends.c b/lib/depends.c
|
|
|
b3c12f |
index 28a4a784d..9e0489bcc 100644
|
|
|
b3c12f |
--- a/lib/depends.c
|
|
|
b3c12f |
+++ b/lib/depends.c
|
|
|
b3c12f |
@@ -80,6 +80,8 @@ static rpmRC headerCheckPayloadFormat(Header h) {
|
|
|
b3c12f |
*/
|
|
|
b3c12f |
if (!payloadfmt) return rc;
|
|
|
b3c12f |
|
|
|
b3c12f |
+ if (rstreq(payloadfmt, "clon")) return rc;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
if (!rstreq(payloadfmt, "cpio")) {
|
|
|
b3c12f |
char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
|
|
|
b3c12f |
if (payloadfmt && rstreq(payloadfmt, "drpm")) {
|
|
|
b3c12f |
diff --git a/lib/fsm.c b/lib/fsm.c
|
|
|
b3c12f |
index 35dcda081..03a716474 100644
|
|
|
b3c12f |
--- a/lib/fsm.c
|
|
|
b3c12f |
+++ b/lib/fsm.c
|
|
|
b3c12f |
@@ -7,6 +7,7 @@
|
|
|
b3c12f |
|
|
|
b3c12f |
#include <utime.h>
|
|
|
b3c12f |
#include <errno.h>
|
|
|
b3c12f |
+#include <stdbool.h>
|
|
|
b3c12f |
#if WITH_CAP
|
|
|
b3c12f |
#include <sys/capability.h>
|
|
|
b3c12f |
#endif
|
|
|
b3c12f |
@@ -18,6 +19,7 @@
|
|
|
b3c12f |
|
|
|
b3c12f |
#include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
|
|
|
b3c12f |
#include "lib/fsm.h"
|
|
|
b3c12f |
+#include "lib/rpmlib.h"
|
|
|
b3c12f |
#include "lib/rpmte_internal.h" /* XXX rpmfs */
|
|
|
b3c12f |
#include "lib/rpmplugins.h" /* rpm plugins hooks */
|
|
|
b3c12f |
#include "lib/rpmug.h"
|
|
|
b3c12f |
@@ -835,7 +837,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
b3c12f |
rpmpsm psm, char ** failedFile)
|
|
|
b3c12f |
{
|
|
|
b3c12f |
FD_t payload = rpmtePayload(te);
|
|
|
b3c12f |
- rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
|
|
|
b3c12f |
+ rpmfi fi;
|
|
|
b3c12f |
rpmfs fs = rpmteGetFileStates(te);
|
|
|
b3c12f |
rpmPlugins plugins = rpmtsPlugins(ts);
|
|
|
b3c12f |
struct stat sb;
|
|
|
b3c12f |
@@ -850,10 +852,21 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
b3c12f |
char *tid = NULL;
|
|
|
b3c12f |
const char *suffix;
|
|
|
b3c12f |
char *fpath = NULL;
|
|
|
b3c12f |
+ Header h = rpmteHeader(te);
|
|
|
b3c12f |
+ const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
|
|
|
b3c12f |
+ bool cpio = true;
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (fi == NULL) {
|
|
|
b3c12f |
- rc = RPMERR_BAD_MAGIC;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (payloadfmt && rstreq(payloadfmt, "clon")) {
|
|
|
b3c12f |
+ cpio = false;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (cpio) {
|
|
|
b3c12f |
+ fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
|
|
|
b3c12f |
+ if (fi == NULL) {
|
|
|
b3c12f |
+ rc = RPMERR_BAD_MAGIC;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ fi = rpmfilesIter(files, RPMFI_ITER_FWD);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
/* transaction id used for temporary path suffix while installing */
|
|
|
b3c12f |
@@ -893,10 +906,20 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
b3c12f |
/* Run fsm file pre hook for all plugins */
|
|
|
b3c12f |
rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
|
|
|
b3c12f |
sb.st_mode, action);
|
|
|
b3c12f |
- if (rc) {
|
|
|
b3c12f |
- skip = 1;
|
|
|
b3c12f |
- } else {
|
|
|
b3c12f |
+ skip = skip || rpmfiFFlags(fi) & RPMFILE_GHOST;
|
|
|
b3c12f |
+ bool plugin_contents = false;
|
|
|
b3c12f |
+ switch (rc) {
|
|
|
b3c12f |
+ case RPMRC_OK:
|
|
|
b3c12f |
setFileState(fs, rpmfiFX(fi));
|
|
|
b3c12f |
+ break;
|
|
|
b3c12f |
+ case RPMRC_PLUGIN_CONTENTS:
|
|
|
b3c12f |
+ plugin_contents = true;
|
|
|
b3c12f |
+ // reduce reads on cpio to this value. Could be zero if
|
|
|
b3c12f |
+ // this is from a hard link.
|
|
|
b3c12f |
+ rc = RPMRC_OK;
|
|
|
b3c12f |
+ break;
|
|
|
b3c12f |
+ default:
|
|
|
b3c12f |
+ skip = 1;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
if (!skip) {
|
|
|
b3c12f |
@@ -926,8 +949,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
b3c12f |
|
|
|
b3c12f |
if (S_ISREG(sb.st_mode)) {
|
|
|
b3c12f |
if (rc == RPMERR_ENOENT) {
|
|
|
b3c12f |
- rc = fsmMkfile(fi, fpath, files, psm, nodigest,
|
|
|
b3c12f |
- &setmeta, &firsthardlink, &firstlinkfile);
|
|
|
b3c12f |
+ if (plugin_contents) {
|
|
|
b3c12f |
+ rc = RPMRC_OK;
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ rc = fsmMkfile(fi, fpath, files, psm, nodigest,
|
|
|
b3c12f |
+ &setmeta, &firsthardlink, &firstlinkfile);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
}
|
|
|
b3c12f |
} else if (S_ISDIR(sb.st_mode)) {
|
|
|
b3c12f |
if (rc == RPMERR_ENOENT) {
|
|
|
b3c12f |
@@ -1011,7 +1038,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
b3c12f |
exit:
|
|
|
b3c12f |
|
|
|
b3c12f |
/* No need to bother with close errors on read */
|
|
|
b3c12f |
- rpmfiArchiveClose(fi);
|
|
|
b3c12f |
+ if (cpio) {
|
|
|
b3c12f |
+ rpmfiArchiveClose(fi);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ h = headerFree(h);
|
|
|
b3c12f |
rpmfiFree(fi);
|
|
|
b3c12f |
Fclose(payload);
|
|
|
b3c12f |
free(tid);
|
|
|
b3c12f |
diff --git a/lib/package.c b/lib/package.c
|
|
|
b3c12f |
index 93a06ebfe..b0c1c2857 100644
|
|
|
b3c12f |
--- a/lib/package.c
|
|
|
b3c12f |
+++ b/lib/package.c
|
|
|
b3c12f |
@@ -407,5 +407,45 @@ rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
|
|
|
b3c12f |
return rc;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
+rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ char *msg = NULL;
|
|
|
b3c12f |
+ hdrblob sigblob = hdrblobCreate();
|
|
|
b3c12f |
+ hdrblob blob = hdrblobCreate();
|
|
|
b3c12f |
+ Header h = NULL;
|
|
|
b3c12f |
+ Header sigh = NULL;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ rpmRC rc = rpmLeadRead(fd, &msg;;
|
|
|
b3c12f |
+ if (rc != RPMRC_OK)
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg;;
|
|
|
b3c12f |
+ if (rc != RPMRC_OK)
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ rc = hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, blob, &msg;;
|
|
|
b3c12f |
+ if (rc != RPMRC_OK)
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ rc = hdrblobImport(sigblob, 0, &sigh, &msg;;
|
|
|
b3c12f |
+ if (rc)
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
|
|
|
b3c12f |
+ rc = hdrblobImport(blob, 0, &h, &msg;;
|
|
|
b3c12f |
+ if (rc)
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
|
|
|
b3c12f |
+ *sigp = headerLink(sigh);
|
|
|
b3c12f |
+ *hdrp = headerLink(h);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+exit:
|
|
|
b3c12f |
+ if (rc != RPMRC_OK && msg)
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg);
|
|
|
b3c12f |
+ hdrblobFree(sigblob);
|
|
|
b3c12f |
+ hdrblobFree(blob);
|
|
|
b3c12f |
+ headerFree(sigh);
|
|
|
b3c12f |
+ headerFree(h);
|
|
|
b3c12f |
+ free(msg);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ return rc;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
diff --git a/lib/rpmlib.h b/lib/rpmlib.h
|
|
|
b3c12f |
index 72ee724e8..4f1a24d14 100644
|
|
|
b3c12f |
--- a/lib/rpmlib.h
|
|
|
b3c12f |
+++ b/lib/rpmlib.h
|
|
|
b3c12f |
@@ -156,6 +156,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg);
|
|
|
b3c12f |
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd,
|
|
|
b3c12f |
const char * fn, Header * hdrp);
|
|
|
b3c12f |
|
|
|
b3c12f |
+/** \ingroup header
|
|
|
b3c12f |
+ * Return package signature, header from file handle, no verification.
|
|
|
b3c12f |
+ * @param fd file handle
|
|
|
b3c12f |
+ * @param[out] sigp address of header (or NULL)
|
|
|
b3c12f |
+ * @param[out] hdrp address of header (or NULL)
|
|
|
b3c12f |
+ * @return RPMRC_OK on success
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
/** \ingroup rpmtrans
|
|
|
b3c12f |
* Install source package.
|
|
|
b3c12f |
* @param ts transaction set
|
|
|
b3c12f |
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
|
|
|
b3c12f |
index 62d75c4cf..c5084d398 100644
|
|
|
b3c12f |
--- a/lib/rpmplugins.c
|
|
|
b3c12f |
+++ b/lib/rpmplugins.c
|
|
|
b3c12f |
@@ -356,13 +356,28 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
|
|
|
b3c12f |
plugin_fsm_file_pre_func hookFunc;
|
|
|
b3c12f |
int i;
|
|
|
b3c12f |
rpmRC rc = RPMRC_OK;
|
|
|
b3c12f |
+ rpmRC hook_rc;
|
|
|
b3c12f |
|
|
|
b3c12f |
for (i = 0; i < plugins->count; i++) {
|
|
|
b3c12f |
rpmPlugin plugin = plugins->plugins[i];
|
|
|
b3c12f |
RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);
|
|
|
b3c12f |
- if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ if (hookFunc) {
|
|
|
b3c12f |
+ hook_rc = hookFunc(plugin, fi, path, file_mode, op);
|
|
|
b3c12f |
+ if (hook_rc == RPMRC_FAIL) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
|
|
|
b3c12f |
+ if (rc == RPMRC_PLUGIN_CONTENTS) {
|
|
|
b3c12f |
+ /*
|
|
|
b3c12f |
+ Another plugin already said it'd handle contents. It's undefined how
|
|
|
b3c12f |
+ these would combine, so treat this as a failure condition.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ /* Plugin will handle content */
|
|
|
b3c12f |
+ rc = RPMRC_PLUGIN_CONTENTS;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
}
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
diff --git a/lib/rpmte.c b/lib/rpmte.c
|
|
|
b3c12f |
index fe9782953..ba06c2985 100644
|
|
|
b3c12f |
--- a/lib/rpmte.c
|
|
|
b3c12f |
+++ b/lib/rpmte.c
|
|
|
b3c12f |
@@ -422,6 +422,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd)
|
|
|
b3c12f |
return NULL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
+FD_t rpmteFd(rpmte te)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ return (te != NULL ? te->fd : NULL);
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
fnpyKey rpmteKey(rpmte te)
|
|
|
b3c12f |
{
|
|
|
b3c12f |
return (te != NULL ? te->key : NULL);
|
|
|
b3c12f |
diff --git a/lib/rpmte.h b/lib/rpmte.h
|
|
|
b3c12f |
index 81acf7a19..6fc0a9f91 100644
|
|
|
b3c12f |
--- a/lib/rpmte.h
|
|
|
b3c12f |
+++ b/lib/rpmte.h
|
|
|
b3c12f |
@@ -209,6 +209,8 @@ const char * rpmteNEVR(rpmte te);
|
|
|
b3c12f |
*/
|
|
|
b3c12f |
const char * rpmteNEVRA(rpmte te);
|
|
|
b3c12f |
|
|
|
b3c12f |
+FD_t rpmteFd(rpmte te);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
/** \ingroup rpmte
|
|
|
b3c12f |
* Retrieve key from transaction element.
|
|
|
b3c12f |
* @param te transaction element
|
|
|
b3c12f |
diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h
|
|
|
b3c12f |
index e8e69b506..af2611e9e 100644
|
|
|
b3c12f |
--- a/lib/rpmtypes.h
|
|
|
b3c12f |
+++ b/lib/rpmtypes.h
|
|
|
b3c12f |
@@ -106,7 +106,8 @@ typedef enum rpmRC_e {
|
|
|
b3c12f |
RPMRC_NOTFOUND = 1, /*!< Generic not found code. */
|
|
|
b3c12f |
RPMRC_FAIL = 2, /*!< Generic failure code. */
|
|
|
b3c12f |
RPMRC_NOTTRUSTED = 3, /*!< Signature is OK, but key is not trusted. */
|
|
|
b3c12f |
- RPMRC_NOKEY = 4 /*!< Public key is unavailable. */
|
|
|
b3c12f |
+ RPMRC_NOKEY = 4, /*!< Public key is unavailable. */
|
|
|
b3c12f |
+ RPMRC_PLUGIN_CONTENTS = 5 /*!< fsm_file_pre plugin is handling content */
|
|
|
b3c12f |
} rpmRC;
|
|
|
b3c12f |
|
|
|
b3c12f |
#ifdef __cplusplus
|
|
|
b3c12f |
diff --git a/macros.in b/macros.in
|
|
|
b3c12f |
index 5778a1f58..15a28c2d2 100644
|
|
|
b3c12f |
--- a/macros.in
|
|
|
b3c12f |
+++ b/macros.in
|
|
|
b3c12f |
@@ -1175,6 +1175,7 @@ package or when debugging this package.\
|
|
|
b3c12f |
|
|
|
b3c12f |
# Transaction plugin macros
|
|
|
b3c12f |
%__plugindir %{_libdir}/rpm-plugins
|
|
|
b3c12f |
+%__transaction_reflink %{__plugindir}/reflink.so
|
|
|
b3c12f |
%__transaction_systemd_inhibit %{__plugindir}/systemd_inhibit.so
|
|
|
b3c12f |
%__transaction_selinux %{__plugindir}/selinux.so
|
|
|
b3c12f |
%__transaction_syslog %{__plugindir}/syslog.so
|
|
|
b3c12f |
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
|
|
|
b3c12f |
index 963d53db4..a21401966 100644
|
|
|
b3c12f |
--- a/plugins/Makefile.am
|
|
|
b3c12f |
+++ b/plugins/Makefile.am
|
|
|
b3c12f |
@@ -33,6 +33,10 @@ prioreset_la_SOURCES = prioreset.c
|
|
|
b3c12f |
prioreset_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
|
|
|
b3c12f |
plugins_LTLIBRARIES += prioreset.la
|
|
|
b3c12f |
|
|
|
b3c12f |
+reflink_la_SOURCES = reflink.c
|
|
|
b3c12f |
+reflink_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
|
|
|
b3c12f |
+plugins_LTLIBRARIES += reflink.la
|
|
|
b3c12f |
+
|
|
|
b3c12f |
syslog_la_SOURCES = syslog.c
|
|
|
b3c12f |
syslog_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
|
|
|
b3c12f |
plugins_LTLIBRARIES += syslog.la
|
|
|
b3c12f |
diff --git a/plugins/reflink.c b/plugins/reflink.c
|
|
|
b3c12f |
new file mode 100644
|
|
|
b3c12f |
index 000000000..d7f19acd9
|
|
|
b3c12f |
--- /dev/null
|
|
|
b3c12f |
+++ b/plugins/reflink.c
|
|
|
b3c12f |
@@ -0,0 +1,340 @@
|
|
|
b3c12f |
+#include "system.h"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include <errno.h>
|
|
|
b3c12f |
+#include <sys/resource.h>
|
|
|
b3c12f |
+#include <unistd.h>
|
|
|
b3c12f |
+#include <sys/types.h>
|
|
|
b3c12f |
+#include <sys/stat.h>
|
|
|
b3c12f |
+#include <fcntl.h>
|
|
|
b3c12f |
+#if defined(__linux__)
|
|
|
b3c12f |
+#include <linux/fs.h> /* For FICLONE */
|
|
|
b3c12f |
+#endif
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include <rpm/rpmlog.h>
|
|
|
b3c12f |
+#include "lib/rpmlib.h"
|
|
|
b3c12f |
+#include "lib/rpmplugin.h"
|
|
|
b3c12f |
+#include "lib/rpmte_internal.h"
|
|
|
b3c12f |
+#include <rpm/rpmfileutil.h>
|
|
|
b3c12f |
+#include "rpmio/rpmio_internal.h"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include "debug.h"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include <sys/ioctl.h>
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+/* use hash table to remember inode -> ix (for rpmfilesFN(ix)) lookups */
|
|
|
b3c12f |
+#undef HASHTYPE
|
|
|
b3c12f |
+#undef HTKEYTYPE
|
|
|
b3c12f |
+#undef HTDATATYPE
|
|
|
b3c12f |
+#define HASHTYPE inodeIndexHash
|
|
|
b3c12f |
+#define HTKEYTYPE rpm_ino_t
|
|
|
b3c12f |
+#define HTDATATYPE int
|
|
|
b3c12f |
+#include "lib/rpmhash.H"
|
|
|
b3c12f |
+#include "lib/rpmhash.C"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+/*
|
|
|
b3c12f |
+We use this in find to indicate a key wasn't found. This is an unrecoverable
|
|
|
b3c12f |
+error, but we can at least show a decent error. 0 is never a valid offset
|
|
|
b3c12f |
+because it's the offset of the start of the file.
|
|
|
b3c12f |
+*/
|
|
|
b3c12f |
+#define NOT_FOUND 0
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#define BUFFER_SIZE (1024 * 128)
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */
|
|
|
b3c12f |
+#define MAGIC 3472329499408095051
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+struct reflink_state_s {
|
|
|
b3c12f |
+ /* Stuff that's used across rpms */
|
|
|
b3c12f |
+ long fundamental_block_size;
|
|
|
b3c12f |
+ char *buffer;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ /* stuff that's used/updated per psm */
|
|
|
b3c12f |
+ uint32_t keys, keysize;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ // table for current rpm, keys * (keysize + sizeof(rpm_loff_t))
|
|
|
b3c12f |
+ unsigned char *table;
|
|
|
b3c12f |
+ FD_t fd;
|
|
|
b3c12f |
+ rpmfiles files;
|
|
|
b3c12f |
+ inodeIndexHash inodeIndexes;
|
|
|
b3c12f |
+};
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+typedef struct reflink_state_s * reflink_state;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static int inodeCmp(rpm_ino_t a, rpm_ino_t b)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ return (a != b);
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static unsigned int inodeId(rpm_ino_t a)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ /* rpm_ino_t is uint32_t so maps safely to unsigned int */
|
|
|
b3c12f |
+ return (unsigned int)a;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) {
|
|
|
b3c12f |
+ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s));
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ /*
|
|
|
b3c12f |
+ IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and
|
|
|
b3c12f |
+ length arguments to be aligned to the fundamental block size.
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ The value of "fundamental block size" is directly related to the system's
|
|
|
b3c12f |
+ page size, so we should use that.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ state->fundamental_block_size = sysconf(_SC_PAGESIZE);
|
|
|
b3c12f |
+ state->buffer = rcalloc(1, BUFFER_SIZE);
|
|
|
b3c12f |
+ rpmPluginSetData(plugin, state);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static void reflink_cleanup(rpmPlugin plugin) {
|
|
|
b3c12f |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
+ free(state->buffer);
|
|
|
b3c12f |
+ free(state);
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {
|
|
|
b3c12f |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
+ state->fd = rpmteFd(te);
|
|
|
b3c12f |
+ if (state->fd == 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n"));
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpm_loff_t current = Ftell(state->fd);
|
|
|
b3c12f |
+ uint64_t magic;
|
|
|
b3c12f |
+ if (Fseek(state->fd, -(sizeof(magic)), SEEK_END) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n"));
|
|
|
b3c12f |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ /* yes this gets a bit repetitive */
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ size_t len = sizeof(magic);
|
|
|
b3c12f |
+ if (Fread(&magic, len, 1, state->fd) != len) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n"));
|
|
|
b3c12f |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (magic != MAGIC) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n"));
|
|
|
b3c12f |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n"));
|
|
|
b3c12f |
+ Header h = rpmteHeader(te);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ /* replace/add header that main fsm.c can read */
|
|
|
b3c12f |
+ headerDel(h, RPMTAG_PAYLOADFORMAT);
|
|
|
b3c12f |
+ headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon");
|
|
|
b3c12f |
+ headerFree(h);
|
|
|
b3c12f |
+ state->files = rpmteFiles(te);
|
|
|
b3c12f |
+ /* tail of file contains offset_table, offset_checksums
|
|
|
b3c12f |
+ then magic
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd);
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpm_loff_t table_start;
|
|
|
b3c12f |
+ len = sizeof(table_start);
|
|
|
b3c12f |
+ if (Fread(&table_start, len, 1, state->fd) != len) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (Fseek(state->fd, table_start, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ len = sizeof(state->keys);
|
|
|
b3c12f |
+ if (Fread(&state->keys, len, 1, state->fd) != len) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ len = sizeof(state->keysize);
|
|
|
b3c12f |
+ if (Fread(&state->keysize, len, 1, state->fd) != len) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize);
|
|
|
b3c12f |
+ // now get digest table if there is a reason to have one.
|
|
|
b3c12f |
+ if (state->keys == 0 || state->keysize == 0) {
|
|
|
b3c12f |
+ // no files (or no digests(!))
|
|
|
b3c12f |
+ state->table = NULL;
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t));
|
|
|
b3c12f |
+ state->table = rcalloc(1, table_size);
|
|
|
b3c12f |
+ if (Fread(state->table, table_size, 1, state->fd) != table_size) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ // seek back to original location
|
|
|
b3c12f |
+ // might not be needed if we seek to offset immediately
|
|
|
b3c12f |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
+ state->files = rpmfilesFree(state->files);
|
|
|
b3c12f |
+ if (state->table) {
|
|
|
b3c12f |
+ free(state->table);
|
|
|
b3c12f |
+ state->table = NULL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (state->inodeIndexes) {
|
|
|
b3c12f |
+ inodeIndexHashFree(state->inodeIndexes);
|
|
|
b3c12f |
+ state->inodeIndexes = NULL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+// have a prototype, warnings system
|
|
|
b3c12f |
+rpm_loff_t find(const unsigned char *digest, reflink_state state);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+rpm_loff_t find(const unsigned char *digest, reflink_state state) {
|
|
|
b3c12f |
+# if defined(__GNUC__)
|
|
|
b3c12f |
+ /* GCC nested function because bsearch's comparison function can't access
|
|
|
b3c12f |
+ state-keysize otherwise
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ int cmpdigest(const void *k1, const void *k2) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
|
|
|
b3c12f |
+ return memcmp(k1, k2, state->keysize);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+# endif
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"), digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t));
|
|
|
b3c12f |
+ char *entry = bsearch(digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t), cmpdigest);
|
|
|
b3c12f |
+ if (entry == NULL) {
|
|
|
b3c12f |
+ return NOT_FOUND;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize);
|
|
|
b3c12f |
+ return offset;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ struct file_clone_range fcr;
|
|
|
b3c12f |
+ rpm_loff_t size;
|
|
|
b3c12f |
+ int dst, rc;
|
|
|
b3c12f |
+ int *hlix;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
+ if (state->table == NULL) {
|
|
|
b3c12f |
+ // no table means rpm is not in reflink format, so leave. Now.
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (op == FA_TOUCH) {
|
|
|
b3c12f |
+ // we're not overwriting an existing file
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ fcr.dest_offset = 0;
|
|
|
b3c12f |
+ if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) {
|
|
|
b3c12f |
+ rpm_ino_t inode = rpmfiFInode(fi);
|
|
|
b3c12f |
+ /* check for hard link entry in table. GetEntry overwrites hlix with the address of the first match */
|
|
|
b3c12f |
+ if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, NULL)) {
|
|
|
b3c12f |
+ // entry is in table, use hard link
|
|
|
b3c12f |
+ char *fn = rpmfilesFN(state->files, hlix[0]);
|
|
|
b3c12f |
+ if (link(fn, path) != 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno));
|
|
|
b3c12f |
+ free(fn);
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ free(fn);
|
|
|
b3c12f |
+ return RPMRC_PLUGIN_CONTENTS;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ /* if we didn't hard link, then we'll track this inode as being created soon */
|
|
|
b3c12f |
+ if (rpmfiFNlink(fi) > 1) {
|
|
|
b3c12f |
+ /* minor optimization: only store files with more than one link */
|
|
|
b3c12f |
+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi));
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ /* derived from wfd_open in fsm.c */
|
|
|
b3c12f |
+ mode_t old_umask = umask(0577);
|
|
|
b3c12f |
+ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
|
|
|
b3c12f |
+ umask(old_umask);
|
|
|
b3c12f |
+ if (dst == -1) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ size = rpmfiFSize(fi);
|
|
|
b3c12f |
+ if (size > 0) {
|
|
|
b3c12f |
+ /* round src_length down to fundamental_block_size multiple */
|
|
|
b3c12f |
+ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size;
|
|
|
b3c12f |
+ if ((size % state->fundamental_block_size) > 0) {
|
|
|
b3c12f |
+ /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */
|
|
|
b3c12f |
+ fcr.src_length += state->fundamental_block_size;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ fcr.src_fd = Fileno(state->fd);
|
|
|
b3c12f |
+ if (fcr.src_fd == -1) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state);
|
|
|
b3c12f |
+ if (fcr.src_offset == NOT_FOUND) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd);
|
|
|
b3c12f |
+ rc = ioctl(dst, FICLONERANGE, &fcr;;
|
|
|
b3c12f |
+ if (rc) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno));
|
|
|
b3c12f |
+ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpm_loff_t left = size;
|
|
|
b3c12f |
+ size_t len, read, written;
|
|
|
b3c12f |
+ while (left) {
|
|
|
b3c12f |
+ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left);
|
|
|
b3c12f |
+ read = Fread(state->buffer, len, 1, state->fd);
|
|
|
b3c12f |
+ if (read != len) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ written = write(dst, state->buffer, len);
|
|
|
b3c12f |
+ if (read != written) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ left -= len;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ /* reflink worked, so truncate */
|
|
|
b3c12f |
+ rc = ftruncate(dst, size);
|
|
|
b3c12f |
+ if (rc) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ return RPMRC_PLUGIN_CONTENTS;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+struct rpmPluginHooks_s reflink_hooks = {
|
|
|
b3c12f |
+ .init = reflink_init,
|
|
|
b3c12f |
+ .cleanup = reflink_cleanup,
|
|
|
b3c12f |
+ .psm_pre = reflink_psm_pre,
|
|
|
b3c12f |
+ .psm_post = reflink_psm_post,
|
|
|
b3c12f |
+ .fsm_file_pre = reflink_fsm_file_pre,
|
|
|
b3c12f |
+};
|
|
|
b3c12f |
diff --git a/rpm2extents.c b/rpm2extents.c
|
|
|
b3c12f |
new file mode 100644
|
|
|
b3c12f |
index 000000000..5662b86a6
|
|
|
b3c12f |
--- /dev/null
|
|
|
b3c12f |
+++ b/rpm2extents.c
|
|
|
b3c12f |
@@ -0,0 +1,519 @@
|
|
|
b3c12f |
+/* rpm2extents: convert payload to inline extents */
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include "system.h"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include <rpm/rpmlib.h> /* rpmReadPackageFile .. */
|
|
|
b3c12f |
+#include <rpm/rpmfi.h>
|
|
|
b3c12f |
+#include <rpm/rpmtag.h>
|
|
|
b3c12f |
+#include <rpm/rpmio.h>
|
|
|
b3c12f |
+#include <rpm/rpmpgp.h>
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include <rpm/rpmts.h>
|
|
|
b3c12f |
+#include "lib/rpmlead.h"
|
|
|
b3c12f |
+#include "lib/signature.h"
|
|
|
b3c12f |
+#include "lib/header_internal.h"
|
|
|
b3c12f |
+#include "rpmio/rpmio_internal.h"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include <unistd.h>
|
|
|
b3c12f |
+#include <sys/types.h>
|
|
|
b3c12f |
+#include <sys/wait.h>
|
|
|
b3c12f |
+#include <signal.h>
|
|
|
b3c12f |
+#include <errno.h>
|
|
|
b3c12f |
+#include <string.h>
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+#include "debug.h"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+/* hash of void * (pointers) to file digests to offsets within output.
|
|
|
b3c12f |
+ The length of the key depends on what the FILEDIGESTALGO is.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+#undef HASHTYPE
|
|
|
b3c12f |
+#undef HTKEYTYPE
|
|
|
b3c12f |
+#undef HTDATATYPE
|
|
|
b3c12f |
+#define HASHTYPE digestSet
|
|
|
b3c12f |
+#define HTKEYTYPE const unsigned char *
|
|
|
b3c12f |
+#include "lib/rpmhash.H"
|
|
|
b3c12f |
+#include "lib/rpmhash.C"
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */
|
|
|
b3c12f |
+#define MAGIC 3472329499408095051
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+struct digestoffset {
|
|
|
b3c12f |
+ const unsigned char * digest;
|
|
|
b3c12f |
+ rpm_loff_t pos;
|
|
|
b3c12f |
+};
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ return (unit - (pos % unit)) % unit;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static int digestor(
|
|
|
b3c12f |
+ FD_t fdi,
|
|
|
b3c12f |
+ FD_t fdo,
|
|
|
b3c12f |
+ FD_t validationo,
|
|
|
b3c12f |
+ uint8_t algos[],
|
|
|
b3c12f |
+ uint32_t algos_len
|
|
|
b3c12f |
+)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ ssize_t fdilength;
|
|
|
b3c12f |
+ const char *filedigest, *algo_name;
|
|
|
b3c12f |
+ size_t filedigest_len, len;
|
|
|
b3c12f |
+ uint32_t algo_name_len, algo_digest_len;
|
|
|
b3c12f |
+ int algo;
|
|
|
b3c12f |
+ rpmRC rc = RPMRC_FAIL;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ for (algo = 0; algo < algos_len; algo++)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fdInitDigest(fdi, algos[algo], 0);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ fdilength = ufdCopy(fdi, fdo);
|
|
|
b3c12f |
+ if (fdilength == -1)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("digest cat failed\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ len = sizeof(fdilength);
|
|
|
b3c12f |
+ if (Fwrite(&fdilength, len, 1, validationo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write input length %zd\n"), fdilength);
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ len = sizeof(algos_len);
|
|
|
b3c12f |
+ if (Fwrite(&algos_len, len, 1, validationo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write number of validation digests\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ for (algo = 0; algo < algos_len; algo++)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]);
|
|
|
b3c12f |
+ algo_name_len = (uint32_t)strlen(algo_name);
|
|
|
b3c12f |
+ algo_digest_len = (uint32_t)filedigest_len;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ len = sizeof(algo_name_len);
|
|
|
b3c12f |
+ if (Fwrite(&algo_name_len, len, 1, validationo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Unable to write validation algo name length\n")
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ len = sizeof(algo_digest_len);
|
|
|
b3c12f |
+ if (Fwrite(&algo_digest_len, len, 1, validationo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Unable to write number of bytes for validation digest\n")
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write validation algo name\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (
|
|
|
b3c12f |
+ Fwrite(
|
|
|
b3c12f |
+ filedigest,
|
|
|
b3c12f |
+ algo_digest_len,
|
|
|
b3c12f |
+ 1,
|
|
|
b3c12f |
+ validationo
|
|
|
b3c12f |
+ ) != algo_digest_len
|
|
|
b3c12f |
+ )
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Unable to write validation digest value %u, %zu\n"),
|
|
|
b3c12f |
+ algo_digest_len,
|
|
|
b3c12f |
+ filedigest_len
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rc = RPMRC_OK;
|
|
|
b3c12f |
+exit:
|
|
|
b3c12f |
+ return rc;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+static rpmRC process_package(FD_t fdi, FD_t validationi)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ uint32_t diglen;
|
|
|
b3c12f |
+ /* GNU C extension: can use diglen from outer context */
|
|
|
b3c12f |
+ int digestSetCmp(const unsigned char * a, const unsigned char * b)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ return memcmp(a, b, diglen);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ unsigned int digestSetHash(const unsigned char * digest)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ /* assumes sizeof(unsigned int) < diglen */
|
|
|
b3c12f |
+ return *(unsigned int *)digest;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ int digestoffsetCmp(const void * a, const void * b)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ return digestSetCmp(
|
|
|
b3c12f |
+ ((struct digestoffset *)a)->digest,
|
|
|
b3c12f |
+ ((struct digestoffset *)b)->digest
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ FD_t fdo;
|
|
|
b3c12f |
+ FD_t gzdi;
|
|
|
b3c12f |
+ Header h, sigh;
|
|
|
b3c12f |
+ long fundamental_block_size = sysconf(_SC_PAGESIZE);
|
|
|
b3c12f |
+ rpmRC rc = RPMRC_OK;
|
|
|
b3c12f |
+ rpm_mode_t mode;
|
|
|
b3c12f |
+ char *rpmio_flags = NULL, *zeros;
|
|
|
b3c12f |
+ const unsigned char *digest;
|
|
|
b3c12f |
+ rpm_loff_t pos, size, pad, validation_pos;
|
|
|
b3c12f |
+ uint32_t offset_ix = 0;
|
|
|
b3c12f |
+ size_t len;
|
|
|
b3c12f |
+ int next = 0;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ fdo = fdDup(STDOUT_FILENO);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (rpmReadPackageRaw(fdi, &sigh, &h))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Error reading package\n"));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (rpmLeadWrite(fdo, h))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Unable to write package lead: %s\n"),
|
|
|
b3c12f |
+ Fstrerror(fdo)
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (rpmWriteSignature(fdo, sigh))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (headerWrite(fdo, h, HEADER_MAGIC_YES))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ /* Retrieve payload size and compression type. */
|
|
|
b3c12f |
+ { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
|
|
|
b3c12f |
+ rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */
|
|
|
b3c12f |
+ free(rpmio_flags);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (gzdi == NULL)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
|
|
|
b3c12f |
+ rpmfi fi = rpmfiNewArchiveReader(
|
|
|
b3c12f |
+ gzdi,
|
|
|
b3c12f |
+ files,
|
|
|
b3c12f |
+ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ /* this is encoded in the file format, so needs to be fixed size (for
|
|
|
b3c12f |
+ now?)
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi));
|
|
|
b3c12f |
+ digestSet ds = digestSetCreate(
|
|
|
b3c12f |
+ rpmfiFC(fi),
|
|
|
b3c12f |
+ digestSetHash,
|
|
|
b3c12f |
+ digestSetCmp,
|
|
|
b3c12f |
+ NULL
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ struct digestoffset offsets[rpmfiFC(fi)];
|
|
|
b3c12f |
+ pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ /* main headers are aligned to 8 byte boundry */
|
|
|
b3c12f |
+ pos += pad_to(pos, 8);
|
|
|
b3c12f |
+ pos += headerSizeof(h, HEADER_MAGIC_YES);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ zeros = xcalloc(fundamental_block_size, 1);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ while (next >= 0)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ next = rpmfiNext(fi);
|
|
|
b3c12f |
+ if (next == RPMERR_ITER_END)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ rc = RPMRC_OK;
|
|
|
b3c12f |
+ break;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ mode = rpmfiFMode(fi);
|
|
|
b3c12f |
+ if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ /* not a regular file, or the archive doesn't contain any content for
|
|
|
b3c12f |
+ this entry
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ continue;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ digest = rpmfiFDigest(fi, NULL, NULL);
|
|
|
b3c12f |
+ if (digestSetGetEntry(ds, digest, NULL))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ /* This specific digest has already been included, so skip it */
|
|
|
b3c12f |
+ continue;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ pad = pad_to(pos, fundamental_block_size);
|
|
|
b3c12f |
+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write padding\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ /* round up to next fundamental_block_size */
|
|
|
b3c12f |
+ pos += pad;
|
|
|
b3c12f |
+ digestSetAddEntry(ds, digest);
|
|
|
b3c12f |
+ offsets[offset_ix].digest = digest;
|
|
|
b3c12f |
+ offsets[offset_ix].pos = pos;
|
|
|
b3c12f |
+ offset_ix++;
|
|
|
b3c12f |
+ size = rpmfiFSize(fi);
|
|
|
b3c12f |
+ rc = rpmfiArchiveReadToFile(fi, fdo, 0);
|
|
|
b3c12f |
+ if (rc != RPMRC_OK)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc);
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ pos += size;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ Fclose(gzdi); /* XXX gzdi == fdi */
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ qsort(
|
|
|
b3c12f |
+ offsets,
|
|
|
b3c12f |
+ (size_t)offset_ix,
|
|
|
b3c12f |
+ sizeof(struct digestoffset),
|
|
|
b3c12f |
+ digestoffsetCmp
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ len = sizeof(offset_ix);
|
|
|
b3c12f |
+ if (Fwrite(&offset_ix, len, 1, fdo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write length of table\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ len = sizeof(diglen);
|
|
|
b3c12f |
+ if (Fwrite(&diglen, len, 1, fdo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write length of digest\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ len = sizeof(rpm_loff_t);
|
|
|
b3c12f |
+ for (int x = 0; x < offset_ix; x++)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write digest\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write offset\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ validation_pos = (
|
|
|
b3c12f |
+ pos + sizeof(offset_ix) + sizeof(diglen) +
|
|
|
b3c12f |
+ offset_ix * (diglen + sizeof(rpm_loff_t))
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ ssize_t validation_len = ufdCopy(validationi, fdo);
|
|
|
b3c12f |
+ if (validation_len == -1)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("digest table ufdCopy failed\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ /* add more padding so the last file can be cloned. It doesn't matter that
|
|
|
b3c12f |
+ the table and validation etc are in this space. In fact, it's pretty
|
|
|
b3c12f |
+ efficient if it is
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ pad = pad_to(
|
|
|
b3c12f |
+ (
|
|
|
b3c12f |
+ validation_pos + validation_len + 2 * sizeof(rpm_loff_t) +
|
|
|
b3c12f |
+ sizeof(uint64_t)
|
|
|
b3c12f |
+ ),
|
|
|
b3c12f |
+ fundamental_block_size
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write final padding\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ zeros = _free(zeros);
|
|
|
b3c12f |
+ if (Fwrite(&pos, len, 1, fdo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write offset of digest table\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (Fwrite(&validation_pos, len, 1, fdo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write offset of validation table\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ uint64_t magic = MAGIC;
|
|
|
b3c12f |
+ len = sizeof(magic);
|
|
|
b3c12f |
+ if (Fwrite(&magic, len, 1, fdo) != len)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write magic\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+exit:
|
|
|
b3c12f |
+ rpmfilesFree(files);
|
|
|
b3c12f |
+ rpmfiFree(fi);
|
|
|
b3c12f |
+ headerFree(h);
|
|
|
b3c12f |
+ return rc;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+int main(int argc, char *argv[])
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ rpmRC rc;
|
|
|
b3c12f |
+ int cprc = 0;
|
|
|
b3c12f |
+ uint8_t algos[argc - 1];
|
|
|
b3c12f |
+ int mainpipefd[2];
|
|
|
b3c12f |
+ int metapipefd[2];
|
|
|
b3c12f |
+ pid_t cpid, w;
|
|
|
b3c12f |
+ int wstatus;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ xsetprogname(argv[0]); /* Portability call -- see system.h */
|
|
|
b3c12f |
+ rpmReadConfigFiles(NULL, NULL);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]);
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (argc == 1)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ for (int x = 0; x < (argc - 1); x++)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"),
|
|
|
b3c12f |
+ argv[x + 1]
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ if (pipe(mainpipefd) == -1)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Main pipe failure\n"));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (pipe(metapipefd) == -1)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("Meta pipe failure\n"));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ cpid = fork();
|
|
|
b3c12f |
+ if (cpid == 0)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ /* child: digestor */
|
|
|
b3c12f |
+ close(mainpipefd[0]);
|
|
|
b3c12f |
+ close(metapipefd[0]);
|
|
|
b3c12f |
+ FD_t fdi = fdDup(STDIN_FILENO);
|
|
|
b3c12f |
+ FD_t fdo = fdDup(mainpipefd[1]);
|
|
|
b3c12f |
+ FD_t validationo = fdDup(metapipefd[1]);
|
|
|
b3c12f |
+ rc = digestor(fdi, fdo, validationo, algos, argc - 1);
|
|
|
b3c12f |
+ Fclose(validationo);
|
|
|
b3c12f |
+ Fclose(fdo);
|
|
|
b3c12f |
+ Fclose(fdi);
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ /* parent: main program */
|
|
|
b3c12f |
+ close(mainpipefd[1]);
|
|
|
b3c12f |
+ close(metapipefd[1]);
|
|
|
b3c12f |
+ FD_t fdi = fdDup(mainpipefd[0]);
|
|
|
b3c12f |
+ FD_t validationi = fdDup(metapipefd[0]);
|
|
|
b3c12f |
+ rc = process_package(fdi, validationi);
|
|
|
b3c12f |
+ Fclose(validationi);
|
|
|
b3c12f |
+ /* fdi is normally closed through the stacked file gzdi in the function. */
|
|
|
b3c12f |
+ /* wait for child process (digestor for stdin) to complete. */
|
|
|
b3c12f |
+ if (rc != RPMRC_OK)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ if (kill(cpid, SIGTERM) != 0)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Failed to kill digest process when main process failed: %s\n"),
|
|
|
b3c12f |
+ strerror(errno)
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ w = waitpid(cpid, &wstatus, 0);
|
|
|
b3c12f |
+ if (w == -1)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr, _("waitpid failed\n"));
|
|
|
b3c12f |
+ cprc = EXIT_FAILURE;
|
|
|
b3c12f |
+ } else if (WIFEXITED(wstatus))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ cprc = WEXITSTATUS(wstatus);
|
|
|
b3c12f |
+ if (cprc != 0)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Digest process non-zero exit code %d\n"),
|
|
|
b3c12f |
+ cprc
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ } else if (WIFSIGNALED(wstatus))
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(
|
|
|
b3c12f |
+ stderr,
|
|
|
b3c12f |
+ _("Digest process was terminated with a signal: %d\n"),
|
|
|
b3c12f |
+ WTERMSIG(wstatus)
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ cprc = EXIT_FAILURE;
|
|
|
b3c12f |
+ } else
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ /* don't think this can happen, but covering all bases */
|
|
|
b3c12f |
+ fprintf(stderr, _("Unhandled circumstance in waitpid\n"));
|
|
|
b3c12f |
+ cprc = EXIT_FAILURE;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (cprc != EXIT_SUCCESS)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (rc != RPMRC_OK)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ /* translate rpmRC into generic failure return code. */
|
|
|
b3c12f |
+ return EXIT_FAILURE;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return EXIT_SUCCESS;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
|
|
|
b3c12f |
index d1d2e7de3..2b58de167 100644
|
|
|
b3c12f |
--- a/rpmio/rpmpgp.c
|
|
|
b3c12f |
+++ b/rpmio/rpmpgp.c
|
|
|
b3c12f |
@@ -298,6 +298,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se)
|
|
|
b3c12f |
return vs->val;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
+int pgpStringVal(pgpValType type, const char *str, uint8_t *val)
|
|
|
b3c12f |
+{
|
|
|
b3c12f |
+ pgpValTbl tbl = pgpValTable(type);
|
|
|
b3c12f |
+ if (tbl == NULL) return -1;
|
|
|
b3c12f |
+ int v = pgpValTok(tbl, str, str + strlen(str));
|
|
|
b3c12f |
+ if (v == -1) return -1;
|
|
|
b3c12f |
+ *val = (uint8_t)v;
|
|
|
b3c12f |
+ return 0;
|
|
|
b3c12f |
+}
|
|
|
b3c12f |
+
|
|
|
b3c12f |
/** \ingroup rpmpgp
|
|
|
b3c12f |
* Decode length from 1, 2, or 5 octet body length encoding, used in
|
|
|
b3c12f |
* new format packet headers and V4 signature subpackets.
|
|
|
b3c12f |
diff --git a/rpmio/rpmpgp.h b/rpmio/rpmpgp.h
|
|
|
b3c12f |
index 1614750d6..4626a2efc 100644
|
|
|
b3c12f |
--- a/rpmio/rpmpgp.h
|
|
|
b3c12f |
+++ b/rpmio/rpmpgp.h
|
|
|
b3c12f |
@@ -973,6 +973,15 @@ typedef rpmFlags rpmDigestFlags;
|
|
|
b3c12f |
*/
|
|
|
b3c12f |
const char * pgpValString(pgpValType type, uint8_t val);
|
|
|
b3c12f |
|
|
|
b3c12f |
+/** \ingroup rpmpgp
|
|
|
b3c12f |
+ * Return OpenPGP value for a string.
|
|
|
b3c12f |
+ * @param type type of value
|
|
|
b3c12f |
+ * @param str string to lookup
|
|
|
b3c12f |
+ * @param[out] val byte value associated with string
|
|
|
b3c12f |
+ * @return 0 on success else -1
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+int pgpStringVal(pgpValType type, const char *str, uint8_t *val);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
/** \ingroup rpmpgp
|
|
|
b3c12f |
* Return (native-endian) integer from big-endian representation.
|
|
|
b3c12f |
* @param s pointer to big-endian integer
|
|
|
b3c12f |
|
|
|
b3c12f |
From 9de362d128634768543e1999763fb1371313c40d Mon Sep 17 00:00:00 2001
|
|
|
b3c12f |
From: Matthew Almond <malmond@fb.com>
|
|
|
b3c12f |
Date: Sun, 31 Jan 2021 12:30:33 -0800
|
|
|
b3c12f |
Subject: [PATCH 2/4] Remove use of bool type for consistency
|
|
|
b3c12f |
|
|
|
b3c12f |
---
|
|
|
b3c12f |
lib/fsm.c | 9 ++++-----
|
|
|
b3c12f |
1 file changed, 4 insertions(+), 5 deletions(-)
|
|
|
b3c12f |
|
|
|
b3c12f |
diff --git a/lib/fsm.c b/lib/fsm.c
|
|
|
b3c12f |
index 03a716474..7966ac2f1 100644
|
|
|
b3c12f |
--- a/lib/fsm.c
|
|
|
b3c12f |
+++ b/lib/fsm.c
|
|
|
b3c12f |
@@ -7,7 +7,6 @@
|
|
|
b3c12f |
|
|
|
b3c12f |
#include <utime.h>
|
|
|
b3c12f |
#include <errno.h>
|
|
|
b3c12f |
-#include <stdbool.h>
|
|
|
b3c12f |
#if WITH_CAP
|
|
|
b3c12f |
#include <sys/capability.h>
|
|
|
b3c12f |
#endif
|
|
|
b3c12f |
@@ -854,10 +853,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
b3c12f |
char *fpath = NULL;
|
|
|
b3c12f |
Header h = rpmteHeader(te);
|
|
|
b3c12f |
const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
|
|
|
b3c12f |
- bool cpio = true;
|
|
|
b3c12f |
+ int cpio = 1;
|
|
|
b3c12f |
|
|
|
b3c12f |
if (payloadfmt && rstreq(payloadfmt, "clon")) {
|
|
|
b3c12f |
- cpio = false;
|
|
|
b3c12f |
+ cpio = 0;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
if (cpio) {
|
|
|
b3c12f |
fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
|
|
|
b3c12f |
@@ -907,13 +906,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
|
|
|
b3c12f |
rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
|
|
|
b3c12f |
sb.st_mode, action);
|
|
|
b3c12f |
skip = skip || rpmfiFFlags(fi) & RPMFILE_GHOST;
|
|
|
b3c12f |
- bool plugin_contents = false;
|
|
|
b3c12f |
+ int plugin_contents = 0;
|
|
|
b3c12f |
switch (rc) {
|
|
|
b3c12f |
case RPMRC_OK:
|
|
|
b3c12f |
setFileState(fs, rpmfiFX(fi));
|
|
|
b3c12f |
break;
|
|
|
b3c12f |
case RPMRC_PLUGIN_CONTENTS:
|
|
|
b3c12f |
- plugin_contents = true;
|
|
|
b3c12f |
+ plugin_contents = 1;
|
|
|
b3c12f |
// reduce reads on cpio to this value. Could be zero if
|
|
|
b3c12f |
// this is from a hard link.
|
|
|
b3c12f |
rc = RPMRC_OK;
|
|
|
b3c12f |
|
|
|
b3c12f |
From 91f7284e961cdbecdfec5beedbce03ee2f0fbd85 Mon Sep 17 00:00:00 2001
|
|
|
b3c12f |
From: Matthew Almond <malmond@fb.com>
|
|
|
b3c12f |
Date: Sun, 31 Jan 2021 13:51:16 -0800
|
|
|
b3c12f |
Subject: [PATCH 3/4] Match formatting/style of existing code
|
|
|
b3c12f |
|
|
|
b3c12f |
The existing code contains some variability in formatting. I'm not sure
|
|
|
b3c12f |
if { is meant to be on the end of the line, or on a new line, but I've
|
|
|
b3c12f |
standardized on the former.
|
|
|
b3c12f |
|
|
|
b3c12f |
The indentation is intended to match the existing convention: 4 column
|
|
|
b3c12f |
indent, but 8 column wide tab characters. This is easy to follow/use in
|
|
|
b3c12f |
vim, but is surprisingly difficult to get right in vscode. I am doing
|
|
|
b3c12f |
this reformat here and now, and future changes will be after this.
|
|
|
b3c12f |
|
|
|
b3c12f |
I'm keen to fold the patches together, but for now, I'm trying to keep
|
|
|
b3c12f |
the history of #1470 linear so everyone can follow along.
|
|
|
b3c12f |
---
|
|
|
b3c12f |
lib/rpmplugins.c | 6 +-
|
|
|
b3c12f |
plugins/reflink.c | 407 ++++++++++++++++++---------------
|
|
|
b3c12f |
rpm2extents.c | 562 ++++++++++++++++++++--------------------------
|
|
|
b3c12f |
3 files changed, 462 insertions(+), 513 deletions(-)
|
|
|
b3c12f |
|
|
|
b3c12f |
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
|
|
|
b3c12f |
index c5084d398..3da3097af 100644
|
|
|
b3c12f |
--- a/lib/rpmplugins.c
|
|
|
b3c12f |
+++ b/lib/rpmplugins.c
|
|
|
b3c12f |
@@ -368,9 +368,9 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
|
|
|
b3c12f |
rc = RPMRC_FAIL;
|
|
|
b3c12f |
} else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
|
|
|
b3c12f |
if (rc == RPMRC_PLUGIN_CONTENTS) {
|
|
|
b3c12f |
- /*
|
|
|
b3c12f |
- Another plugin already said it'd handle contents. It's undefined how
|
|
|
b3c12f |
- these would combine, so treat this as a failure condition.
|
|
|
b3c12f |
+ /* Another plugin already said it'd handle contents. It's
|
|
|
b3c12f |
+ * undefined how these would combine, so treat this as a
|
|
|
b3c12f |
+ * failure condition.
|
|
|
b3c12f |
*/
|
|
|
b3c12f |
rc = RPMRC_FAIL;
|
|
|
b3c12f |
} else {
|
|
|
b3c12f |
diff --git a/plugins/reflink.c b/plugins/reflink.c
|
|
|
b3c12f |
index d7f19acd9..9eaa87094 100644
|
|
|
b3c12f |
--- a/plugins/reflink.c
|
|
|
b3c12f |
+++ b/plugins/reflink.c
|
|
|
b3c12f |
@@ -32,31 +32,32 @@
|
|
|
b3c12f |
#include "lib/rpmhash.H"
|
|
|
b3c12f |
#include "lib/rpmhash.C"
|
|
|
b3c12f |
|
|
|
b3c12f |
-/*
|
|
|
b3c12f |
-We use this in find to indicate a key wasn't found. This is an unrecoverable
|
|
|
b3c12f |
-error, but we can at least show a decent error. 0 is never a valid offset
|
|
|
b3c12f |
-because it's the offset of the start of the file.
|
|
|
b3c12f |
-*/
|
|
|
b3c12f |
+/* We use this in find to indicate a key wasn't found. This is an
|
|
|
b3c12f |
+ * unrecoverable error, but we can at least show a decent error. 0 is never a
|
|
|
b3c12f |
+ * valid offset because it's the offset of the start of the file.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
#define NOT_FOUND 0
|
|
|
b3c12f |
|
|
|
b3c12f |
#define BUFFER_SIZE (1024 * 128)
|
|
|
b3c12f |
|
|
|
b3c12f |
-/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */
|
|
|
b3c12f |
+/* magic value at end of file (64 bits) that indicates this is a transcoded
|
|
|
b3c12f |
+ * rpm.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
#define MAGIC 3472329499408095051
|
|
|
b3c12f |
|
|
|
b3c12f |
struct reflink_state_s {
|
|
|
b3c12f |
- /* Stuff that's used across rpms */
|
|
|
b3c12f |
- long fundamental_block_size;
|
|
|
b3c12f |
- char *buffer;
|
|
|
b3c12f |
+ /* Stuff that's used across rpms */
|
|
|
b3c12f |
+ long fundamental_block_size;
|
|
|
b3c12f |
+ char *buffer;
|
|
|
b3c12f |
|
|
|
b3c12f |
- /* stuff that's used/updated per psm */
|
|
|
b3c12f |
- uint32_t keys, keysize;
|
|
|
b3c12f |
+ /* stuff that's used/updated per psm */
|
|
|
b3c12f |
+ uint32_t keys, keysize;
|
|
|
b3c12f |
|
|
|
b3c12f |
- // table for current rpm, keys * (keysize + sizeof(rpm_loff_t))
|
|
|
b3c12f |
- unsigned char *table;
|
|
|
b3c12f |
- FD_t fd;
|
|
|
b3c12f |
- rpmfiles files;
|
|
|
b3c12f |
- inodeIndexHash inodeIndexes;
|
|
|
b3c12f |
+ /* table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) */
|
|
|
b3c12f |
+ unsigned char *table;
|
|
|
b3c12f |
+ FD_t fd;
|
|
|
b3c12f |
+ rpmfiles files;
|
|
|
b3c12f |
+ inodeIndexHash inodeIndexes;
|
|
|
b3c12f |
};
|
|
|
b3c12f |
|
|
|
b3c12f |
typedef struct reflink_state_s * reflink_state;
|
|
|
b3c12f |
@@ -73,60 +74,62 @@ static unsigned int inodeId(rpm_ino_t a)
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) {
|
|
|
b3c12f |
- reflink_state state = rcalloc(1, sizeof(struct reflink_state_s));
|
|
|
b3c12f |
+ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s));
|
|
|
b3c12f |
|
|
|
b3c12f |
- /*
|
|
|
b3c12f |
- IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and
|
|
|
b3c12f |
- length arguments to be aligned to the fundamental block size.
|
|
|
b3c12f |
+ /* IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset
|
|
|
b3c12f |
+ * and length arguments to be aligned to the fundamental block size.
|
|
|
b3c12f |
+ *
|
|
|
b3c12f |
+ * The value of "fundamental block size" is directly related to the
|
|
|
b3c12f |
+ * system's page size, so we should use that.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ state->fundamental_block_size = sysconf(_SC_PAGESIZE);
|
|
|
b3c12f |
+ state->buffer = rcalloc(1, BUFFER_SIZE);
|
|
|
b3c12f |
+ rpmPluginSetData(plugin, state);
|
|
|
b3c12f |
|
|
|
b3c12f |
- The value of "fundamental block size" is directly related to the system's
|
|
|
b3c12f |
- page size, so we should use that.
|
|
|
b3c12f |
- */
|
|
|
b3c12f |
- state->fundamental_block_size = sysconf(_SC_PAGESIZE);
|
|
|
b3c12f |
- state->buffer = rcalloc(1, BUFFER_SIZE);
|
|
|
b3c12f |
- rpmPluginSetData(plugin, state);
|
|
|
b3c12f |
-
|
|
|
b3c12f |
- return RPMRC_OK;
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
static void reflink_cleanup(rpmPlugin plugin) {
|
|
|
b3c12f |
- reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
- free(state->buffer);
|
|
|
b3c12f |
- free(state);
|
|
|
b3c12f |
+ reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
+ free(state->buffer);
|
|
|
b3c12f |
+ free(state);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {
|
|
|
b3c12f |
reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
state->fd = rpmteFd(te);
|
|
|
b3c12f |
if (state->fd == 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n"));
|
|
|
b3c12f |
- return RPMRC_OK;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n"));
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
rpm_loff_t current = Ftell(state->fd);
|
|
|
b3c12f |
uint64_t magic;
|
|
|
b3c12f |
if (Fseek(state->fd, -(sizeof(magic)), SEEK_END) < 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n"));
|
|
|
b3c12f |
- if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
- /* yes this gets a bit repetitive */
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n"));
|
|
|
b3c12f |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ /* yes this gets a bit repetitive */
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
size_t len = sizeof(magic);
|
|
|
b3c12f |
if (Fread(&magic, len, 1, state->fd) != len) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n"));
|
|
|
b3c12f |
- if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n"));
|
|
|
b3c12f |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
if (magic != MAGIC) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n"));
|
|
|
b3c12f |
- if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- return RPMRC_OK;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n"));
|
|
|
b3c12f |
+ if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n"));
|
|
|
b3c12f |
Header h = rpmteHeader(te);
|
|
|
b3c12f |
@@ -136,53 +139,60 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {
|
|
|
b3c12f |
headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon");
|
|
|
b3c12f |
headerFree(h);
|
|
|
b3c12f |
state->files = rpmteFiles(te);
|
|
|
b3c12f |
- /* tail of file contains offset_table, offset_checksums
|
|
|
b3c12f |
- then magic
|
|
|
b3c12f |
- */
|
|
|
b3c12f |
+ /* tail of file contains offset_table, offset_checksums then magic */
|
|
|
b3c12f |
if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd);
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"),
|
|
|
b3c12f |
+ state->fd);
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
rpm_loff_t table_start;
|
|
|
b3c12f |
len = sizeof(table_start);
|
|
|
b3c12f |
if (Fread(&table_start, len, 1, state->fd) != len) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
if (Fseek(state->fd, table_start, SEEK_SET) < 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
len = sizeof(state->keys);
|
|
|
b3c12f |
if (Fread(&state->keys, len, 1, state->fd) != len) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
len = sizeof(state->keysize);
|
|
|
b3c12f |
if (Fread(&state->keysize, len, 1, state->fd) != len) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
- rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize);
|
|
|
b3c12f |
- // now get digest table if there is a reason to have one.
|
|
|
b3c12f |
+ rpmlog(
|
|
|
b3c12f |
+ RPMLOG_DEBUG,
|
|
|
b3c12f |
+ _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"),
|
|
|
b3c12f |
+ table_start, state->keys, state->keysize
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
+ /* now get digest table if there is a reason to have one. */
|
|
|
b3c12f |
if (state->keys == 0 || state->keysize == 0) {
|
|
|
b3c12f |
- // no files (or no digests(!))
|
|
|
b3c12f |
- state->table = NULL;
|
|
|
b3c12f |
+ /* no files (or no digests(!)) */
|
|
|
b3c12f |
+ state->table = NULL;
|
|
|
b3c12f |
} else {
|
|
|
b3c12f |
- int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t));
|
|
|
b3c12f |
- state->table = rcalloc(1, table_size);
|
|
|
b3c12f |
- if (Fread(state->table, table_size, 1, state->fd) != table_size) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL);
|
|
|
b3c12f |
+ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t));
|
|
|
b3c12f |
+ state->table = rcalloc(1, table_size);
|
|
|
b3c12f |
+ if (Fread(state->table, table_size, 1, state->fd) != table_size) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ state->inodeIndexes = inodeIndexHashCreate(
|
|
|
b3c12f |
+ state->keys, inodeId, inodeCmp, NULL, NULL
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
- // seek back to original location
|
|
|
b3c12f |
- // might not be needed if we seek to offset immediately
|
|
|
b3c12f |
+ /* Seek back to original location.
|
|
|
b3c12f |
+ * Might not be needed if we seek to offset immediately
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
if (Fseek(state->fd, current, SEEK_SET) < 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: unable to seek back to original location\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
@@ -192,40 +202,45 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res)
|
|
|
b3c12f |
reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
state->files = rpmfilesFree(state->files);
|
|
|
b3c12f |
if (state->table) {
|
|
|
b3c12f |
- free(state->table);
|
|
|
b3c12f |
- state->table = NULL;
|
|
|
b3c12f |
+ free(state->table);
|
|
|
b3c12f |
+ state->table = NULL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
if (state->inodeIndexes) {
|
|
|
b3c12f |
- inodeIndexHashFree(state->inodeIndexes);
|
|
|
b3c12f |
- state->inodeIndexes = NULL;
|
|
|
b3c12f |
+ inodeIndexHashFree(state->inodeIndexes);
|
|
|
b3c12f |
+ state->inodeIndexes = NULL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
|
|
|
b3c12f |
-// have a prototype, warnings system
|
|
|
b3c12f |
+/* have a prototype, warnings system */
|
|
|
b3c12f |
rpm_loff_t find(const unsigned char *digest, reflink_state state);
|
|
|
b3c12f |
|
|
|
b3c12f |
rpm_loff_t find(const unsigned char *digest, reflink_state state) {
|
|
|
b3c12f |
# if defined(__GNUC__)
|
|
|
b3c12f |
- /* GCC nested function because bsearch's comparison function can't access
|
|
|
b3c12f |
- state-keysize otherwise
|
|
|
b3c12f |
- */
|
|
|
b3c12f |
- int cmpdigest(const void *k1, const void *k2) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
|
|
|
b3c12f |
- return memcmp(k1, k2, state->keysize);
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
+ /* GCC nested function because bsearch's comparison function can't access
|
|
|
b3c12f |
+ * state-keysize otherwise
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ int cmpdigest(const void *k1, const void *k2) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
|
|
|
b3c12f |
+ return memcmp(k1, k2, state->keysize);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
# endif
|
|
|
b3c12f |
- rpmlog(RPMLOG_DEBUG, _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"), digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t));
|
|
|
b3c12f |
- char *entry = bsearch(digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t), cmpdigest);
|
|
|
b3c12f |
- if (entry == NULL) {
|
|
|
b3c12f |
- return NOT_FOUND;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize);
|
|
|
b3c12f |
- return offset;
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG,
|
|
|
b3c12f |
+ _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"),
|
|
|
b3c12f |
+ digest, state->table, state->keys,
|
|
|
b3c12f |
+ state->keysize + sizeof(rpm_loff_t));
|
|
|
b3c12f |
+ char *entry = bsearch(digest, state->table, state->keys,
|
|
|
b3c12f |
+ state->keysize + sizeof(rpm_loff_t), cmpdigest);
|
|
|
b3c12f |
+ if (entry == NULL) {
|
|
|
b3c12f |
+ return NOT_FOUND;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize);
|
|
|
b3c12f |
+ return offset;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
-static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op)
|
|
|
b3c12f |
+static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path,
|
|
|
b3c12f |
+ mode_t file_mode, rpmFsmOp op)
|
|
|
b3c12f |
{
|
|
|
b3c12f |
struct file_clone_range fcr;
|
|
|
b3c12f |
rpm_loff_t size;
|
|
|
b3c12f |
@@ -234,99 +249,119 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path,
|
|
|
b3c12f |
|
|
|
b3c12f |
reflink_state state = rpmPluginGetData(plugin);
|
|
|
b3c12f |
if (state->table == NULL) {
|
|
|
b3c12f |
- // no table means rpm is not in reflink format, so leave. Now.
|
|
|
b3c12f |
- return RPMRC_OK;
|
|
|
b3c12f |
+ /* no table means rpm is not in reflink format, so leave. Now. */
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
if (op == FA_TOUCH) {
|
|
|
b3c12f |
- // we're not overwriting an existing file
|
|
|
b3c12f |
- return RPMRC_OK;
|
|
|
b3c12f |
+ /* we're not overwriting an existing file. */
|
|
|
b3c12f |
+ return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
fcr.dest_offset = 0;
|
|
|
b3c12f |
if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) {
|
|
|
b3c12f |
- rpm_ino_t inode = rpmfiFInode(fi);
|
|
|
b3c12f |
- /* check for hard link entry in table. GetEntry overwrites hlix with the address of the first match */
|
|
|
b3c12f |
- if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, NULL)) {
|
|
|
b3c12f |
- // entry is in table, use hard link
|
|
|
b3c12f |
- char *fn = rpmfilesFN(state->files, hlix[0]);
|
|
|
b3c12f |
- if (link(fn, path) != 0) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno));
|
|
|
b3c12f |
- free(fn);
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- free(fn);
|
|
|
b3c12f |
- return RPMRC_PLUGIN_CONTENTS;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- /* if we didn't hard link, then we'll track this inode as being created soon */
|
|
|
b3c12f |
- if (rpmfiFNlink(fi) > 1) {
|
|
|
b3c12f |
- /* minor optimization: only store files with more than one link */
|
|
|
b3c12f |
- inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi));
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- /* derived from wfd_open in fsm.c */
|
|
|
b3c12f |
- mode_t old_umask = umask(0577);
|
|
|
b3c12f |
- dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
|
|
|
b3c12f |
- umask(old_umask);
|
|
|
b3c12f |
- if (dst == -1) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- size = rpmfiFSize(fi);
|
|
|
b3c12f |
- if (size > 0) {
|
|
|
b3c12f |
- /* round src_length down to fundamental_block_size multiple */
|
|
|
b3c12f |
- fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size;
|
|
|
b3c12f |
- if ((size % state->fundamental_block_size) > 0) {
|
|
|
b3c12f |
- /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */
|
|
|
b3c12f |
- fcr.src_length += state->fundamental_block_size;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- fcr.src_fd = Fileno(state->fd);
|
|
|
b3c12f |
- if (fcr.src_fd == -1) {
|
|
|
b3c12f |
- close(dst);
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state);
|
|
|
b3c12f |
- if (fcr.src_offset == NOT_FOUND) {
|
|
|
b3c12f |
- close(dst);
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: digest not found\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd);
|
|
|
b3c12f |
- rc = ioctl(dst, FICLONERANGE, &fcr;;
|
|
|
b3c12f |
- if (rc) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno));
|
|
|
b3c12f |
- if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) {
|
|
|
b3c12f |
- close(dst);
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- rpm_loff_t left = size;
|
|
|
b3c12f |
- size_t len, read, written;
|
|
|
b3c12f |
- while (left) {
|
|
|
b3c12f |
- len = (left > BUFFER_SIZE ? BUFFER_SIZE : left);
|
|
|
b3c12f |
- read = Fread(state->buffer, len, 1, state->fd);
|
|
|
b3c12f |
- if (read != len) {
|
|
|
b3c12f |
- close(dst);
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- written = write(dst, state->buffer, len);
|
|
|
b3c12f |
- if (read != written) {
|
|
|
b3c12f |
- close(dst);
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n"));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- left -= len;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- } else {
|
|
|
b3c12f |
- /* reflink worked, so truncate */
|
|
|
b3c12f |
- rc = ftruncate(dst, size);
|
|
|
b3c12f |
- if (rc) {
|
|
|
b3c12f |
- rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno));
|
|
|
b3c12f |
- return RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- close(dst);
|
|
|
b3c12f |
- return RPMRC_PLUGIN_CONTENTS;
|
|
|
b3c12f |
+ rpm_ino_t inode = rpmfiFInode(fi);
|
|
|
b3c12f |
+ /* check for hard link entry in table. GetEntry overwrites hlix with
|
|
|
b3c12f |
+ * the address of the first match.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL,
|
|
|
b3c12f |
+ NULL)) {
|
|
|
b3c12f |
+ /* entry is in table, use hard link */
|
|
|
b3c12f |
+ char *fn = rpmfilesFN(state->files, hlix[0]);
|
|
|
b3c12f |
+ if (link(fn, path) != 0) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: Unable to hard link %s -> %s due to %s\n"),
|
|
|
b3c12f |
+ fn, path, strerror(errno));
|
|
|
b3c12f |
+ free(fn);
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ free(fn);
|
|
|
b3c12f |
+ return RPMRC_PLUGIN_CONTENTS;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ /* if we didn't hard link, then we'll track this inode as being
|
|
|
b3c12f |
+ * created soon
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ if (rpmfiFNlink(fi) > 1) {
|
|
|
b3c12f |
+ /* minor optimization: only store files with more than one link */
|
|
|
b3c12f |
+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi));
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ /* derived from wfd_open in fsm.c */
|
|
|
b3c12f |
+ mode_t old_umask = umask(0577);
|
|
|
b3c12f |
+ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
|
|
|
b3c12f |
+ umask(old_umask);
|
|
|
b3c12f |
+ if (dst == -1) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: Unable to open %s for writing due to %s, flags = %x\n"),
|
|
|
b3c12f |
+ path, strerror(errno), rpmfiFFlags(fi));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ size = rpmfiFSize(fi);
|
|
|
b3c12f |
+ if (size > 0) {
|
|
|
b3c12f |
+ /* round src_length down to fundamental_block_size multiple */
|
|
|
b3c12f |
+ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size;
|
|
|
b3c12f |
+ if ((size % state->fundamental_block_size) > 0) {
|
|
|
b3c12f |
+ /* round up to next fundamental_block_size. We expect the data
|
|
|
b3c12f |
+ * in the rpm to be similarly padded.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ fcr.src_length += state->fundamental_block_size;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ fcr.src_fd = Fileno(state->fd);
|
|
|
b3c12f |
+ if (fcr.src_fd == -1) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state);
|
|
|
b3c12f |
+ if (fcr.src_offset == NOT_FOUND) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpmlog(RPMLOG_DEBUG,
|
|
|
b3c12f |
+ _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"),
|
|
|
b3c12f |
+ fcr.src_length, fcr.src_offset, path, size, fcr.src_fd);
|
|
|
b3c12f |
+ rc = ioctl(dst, FICLONERANGE, &fcr;;
|
|
|
b3c12f |
+ if (rc) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_WARNING,
|
|
|
b3c12f |
+ _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"),
|
|
|
b3c12f |
+ path, rc, errno, strerror(errno));
|
|
|
b3c12f |
+ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: unable to seek on copying bits\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ rpm_loff_t left = size;
|
|
|
b3c12f |
+ size_t len, read, written;
|
|
|
b3c12f |
+ while (left) {
|
|
|
b3c12f |
+ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left);
|
|
|
b3c12f |
+ read = Fread(state->buffer, len, 1, state->fd);
|
|
|
b3c12f |
+ if (read != len) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: short read on copying bits\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ written = write(dst, state->buffer, len);
|
|
|
b3c12f |
+ if (read != written) {
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: short write on copying bits\n"));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ left -= len;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ /* reflink worked, so truncate */
|
|
|
b3c12f |
+ rc = ftruncate(dst, size);
|
|
|
b3c12f |
+ if (rc) {
|
|
|
b3c12f |
+ rpmlog(RPMLOG_ERR,
|
|
|
b3c12f |
+ _("reflink: Unable to truncate %s to %ld due to %s\n"),
|
|
|
b3c12f |
+ path, size, strerror(errno));
|
|
|
b3c12f |
+ return RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ close(dst);
|
|
|
b3c12f |
+ return RPMRC_PLUGIN_CONTENTS;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
return RPMRC_OK;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
diff --git a/rpm2extents.c b/rpm2extents.c
|
|
|
b3c12f |
index 5662b86a6..c111be0a2 100644
|
|
|
b3c12f |
--- a/rpm2extents.c
|
|
|
b3c12f |
+++ b/rpm2extents.c
|
|
|
b3c12f |
@@ -24,7 +24,7 @@
|
|
|
b3c12f |
#include "debug.h"
|
|
|
b3c12f |
|
|
|
b3c12f |
/* hash of void * (pointers) to file digests to offsets within output.
|
|
|
b3c12f |
- The length of the key depends on what the FILEDIGESTALGO is.
|
|
|
b3c12f |
+ * The length of the key depends on what the FILEDIGESTALGO is.
|
|
|
b3c12f |
*/
|
|
|
b3c12f |
#undef HASHTYPE
|
|
|
b3c12f |
#undef HTKEYTYPE
|
|
|
b3c12f |
@@ -34,7 +34,9 @@
|
|
|
b3c12f |
#include "lib/rpmhash.H"
|
|
|
b3c12f |
#include "lib/rpmhash.C"
|
|
|
b3c12f |
|
|
|
b3c12f |
-/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */
|
|
|
b3c12f |
+/* magic value at end of file (64 bits) that indicates this is a transcoded
|
|
|
b3c12f |
+ * rpm.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
#define MAGIC 3472329499408095051
|
|
|
b3c12f |
|
|
|
b3c12f |
struct digestoffset {
|
|
|
b3c12f |
@@ -64,77 +66,54 @@ static int digestor(
|
|
|
b3c12f |
int algo;
|
|
|
b3c12f |
rpmRC rc = RPMRC_FAIL;
|
|
|
b3c12f |
|
|
|
b3c12f |
- for (algo = 0; algo < algos_len; algo++)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fdInitDigest(fdi, algos[algo], 0);
|
|
|
b3c12f |
+ for (algo = 0; algo < algos_len; algo++) {
|
|
|
b3c12f |
+ fdInitDigest(fdi, algos[algo], 0);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
fdilength = ufdCopy(fdi, fdo);
|
|
|
b3c12f |
- if (fdilength == -1)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("digest cat failed\n"));
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (fdilength == -1) {
|
|
|
b3c12f |
+ fprintf(stderr, _("digest cat failed\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
len = sizeof(fdilength);
|
|
|
b3c12f |
- if (Fwrite(&fdilength, len, 1, validationo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write input length %zd\n"), fdilength);
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (Fwrite(&fdilength, len, 1, validationo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write input length %zd\n"), fdilength);
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
len = sizeof(algos_len);
|
|
|
b3c12f |
- if (Fwrite(&algos_len, len, 1, validationo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write number of validation digests\n"));
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (Fwrite(&algos_len, len, 1, validationo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write number of validation digests\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
- for (algo = 0; algo < algos_len; algo++)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0);
|
|
|
b3c12f |
-
|
|
|
b3c12f |
- algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]);
|
|
|
b3c12f |
- algo_name_len = (uint32_t)strlen(algo_name);
|
|
|
b3c12f |
- algo_digest_len = (uint32_t)filedigest_len;
|
|
|
b3c12f |
-
|
|
|
b3c12f |
- len = sizeof(algo_name_len);
|
|
|
b3c12f |
- if (Fwrite(&algo_name_len, len, 1, validationo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Unable to write validation algo name length\n")
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- len = sizeof(algo_digest_len);
|
|
|
b3c12f |
- if (Fwrite(&algo_digest_len, len, 1, validationo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Unable to write number of bytes for validation digest\n")
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write validation algo name\n"));
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- if (
|
|
|
b3c12f |
- Fwrite(
|
|
|
b3c12f |
- filedigest,
|
|
|
b3c12f |
- algo_digest_len,
|
|
|
b3c12f |
- 1,
|
|
|
b3c12f |
- validationo
|
|
|
b3c12f |
- ) != algo_digest_len
|
|
|
b3c12f |
- )
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Unable to write validation digest value %u, %zu\n"),
|
|
|
b3c12f |
- algo_digest_len,
|
|
|
b3c12f |
- filedigest_len
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
+ for (algo = 0; algo < algos_len; algo++) {
|
|
|
b3c12f |
+ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0);
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]);
|
|
|
b3c12f |
+ algo_name_len = (uint32_t)strlen(algo_name);
|
|
|
b3c12f |
+ algo_digest_len = (uint32_t)filedigest_len;
|
|
|
b3c12f |
+
|
|
|
b3c12f |
+ len = sizeof(algo_name_len);
|
|
|
b3c12f |
+ if (Fwrite(&algo_name_len, len, 1, validationo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Unable to write validation algo name length\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ len = sizeof(algo_digest_len);
|
|
|
b3c12f |
+ if (Fwrite(&algo_digest_len, len, 1, validationo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Unable to write number of bytes for validation digest\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write validation algo name\n"));
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (Fwrite(filedigest, algo_digest_len, 1, validationo ) != algo_digest_len) {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Unable to write validation digest value %u, %zu\n"),
|
|
|
b3c12f |
+ algo_digest_len, filedigest_len);
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
}
|
|
|
b3c12f |
rc = RPMRC_OK;
|
|
|
b3c12f |
exit:
|
|
|
b3c12f |
@@ -145,23 +124,20 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
|
|
|
b3c12f |
{
|
|
|
b3c12f |
uint32_t diglen;
|
|
|
b3c12f |
/* GNU C extension: can use diglen from outer context */
|
|
|
b3c12f |
- int digestSetCmp(const unsigned char * a, const unsigned char * b)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- return memcmp(a, b, diglen);
|
|
|
b3c12f |
+ int digestSetCmp(const unsigned char * a, const unsigned char * b) {
|
|
|
b3c12f |
+ return memcmp(a, b, diglen);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
- unsigned int digestSetHash(const unsigned char * digest)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
+ unsigned int digestSetHash(const unsigned char * digest) {
|
|
|
b3c12f |
/* assumes sizeof(unsigned int) < diglen */
|
|
|
b3c12f |
return *(unsigned int *)digest;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
- int digestoffsetCmp(const void * a, const void * b)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- return digestSetCmp(
|
|
|
b3c12f |
- ((struct digestoffset *)a)->digest,
|
|
|
b3c12f |
- ((struct digestoffset *)b)->digest
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
+ int digestoffsetCmp(const void * a, const void * b) {
|
|
|
b3c12f |
+ return digestSetCmp(
|
|
|
b3c12f |
+ ((struct digestoffset *)a)->digest,
|
|
|
b3c12f |
+ ((struct digestoffset *)b)->digest
|
|
|
b3c12f |
+ );
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
FD_t fdo;
|
|
|
b3c12f |
@@ -179,65 +155,52 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
|
|
|
b3c12f |
|
|
|
b3c12f |
fdo = fdDup(STDOUT_FILENO);
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (rpmReadPackageRaw(fdi, &sigh, &h))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Error reading package\n"));
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (rpmReadPackageRaw(fdi, &sigh, &h)) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Error reading package\n"));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
if (rpmLeadWrite(fdo, h))
|
|
|
b3c12f |
{
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Unable to write package lead: %s\n"),
|
|
|
b3c12f |
- Fstrerror(fdo)
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write package lead: %s\n"),
|
|
|
b3c12f |
+ Fstrerror(fdo));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (rpmWriteSignature(fdo, sigh))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo));
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (rpmWriteSignature(fdo, sigh)) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (headerWrite(fdo, h, HEADER_MAGIC_YES))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo));
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
/* Retrieve payload size and compression type. */
|
|
|
b3c12f |
- { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
|
|
|
b3c12f |
- rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
|
|
|
b3c12f |
+ rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */
|
|
|
b3c12f |
free(rpmio_flags);
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (gzdi == NULL)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (gzdi == NULL) {
|
|
|
b3c12f |
+ fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
|
|
|
b3c12f |
- rpmfi fi = rpmfiNewArchiveReader(
|
|
|
b3c12f |
- gzdi,
|
|
|
b3c12f |
- files,
|
|
|
b3c12f |
- RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
+ rpmfi fi = rpmfiNewArchiveReader(gzdi, files,
|
|
|
b3c12f |
+ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);
|
|
|
b3c12f |
|
|
|
b3c12f |
/* this is encoded in the file format, so needs to be fixed size (for
|
|
|
b3c12f |
- now?)
|
|
|
b3c12f |
- */
|
|
|
b3c12f |
+ * now?)
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi));
|
|
|
b3c12f |
- digestSet ds = digestSetCreate(
|
|
|
b3c12f |
- rpmfiFC(fi),
|
|
|
b3c12f |
- digestSetHash,
|
|
|
b3c12f |
- digestSetCmp,
|
|
|
b3c12f |
- NULL
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
+ digestSet ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp,
|
|
|
b3c12f |
+ NULL);
|
|
|
b3c12f |
struct digestoffset offsets[rpmfiFC(fi)];
|
|
|
b3c12f |
pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES);
|
|
|
b3c12f |
|
|
|
b3c12f |
@@ -247,139 +210,114 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
|
|
|
b3c12f |
|
|
|
b3c12f |
zeros = xcalloc(fundamental_block_size, 1);
|
|
|
b3c12f |
|
|
|
b3c12f |
- while (next >= 0)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- next = rpmfiNext(fi);
|
|
|
b3c12f |
- if (next == RPMERR_ITER_END)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- rc = RPMRC_OK;
|
|
|
b3c12f |
- break;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- mode = rpmfiFMode(fi);
|
|
|
b3c12f |
- if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- /* not a regular file, or the archive doesn't contain any content for
|
|
|
b3c12f |
- this entry
|
|
|
b3c12f |
- */
|
|
|
b3c12f |
- continue;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- digest = rpmfiFDigest(fi, NULL, NULL);
|
|
|
b3c12f |
- if (digestSetGetEntry(ds, digest, NULL))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- /* This specific digest has already been included, so skip it */
|
|
|
b3c12f |
- continue;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- pad = pad_to(pos, fundamental_block_size);
|
|
|
b3c12f |
- if (Fwrite(zeros, sizeof(char), pad, fdo) != pad)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write padding\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- /* round up to next fundamental_block_size */
|
|
|
b3c12f |
- pos += pad;
|
|
|
b3c12f |
- digestSetAddEntry(ds, digest);
|
|
|
b3c12f |
- offsets[offset_ix].digest = digest;
|
|
|
b3c12f |
- offsets[offset_ix].pos = pos;
|
|
|
b3c12f |
- offset_ix++;
|
|
|
b3c12f |
- size = rpmfiFSize(fi);
|
|
|
b3c12f |
- rc = rpmfiArchiveReadToFile(fi, fdo, 0);
|
|
|
b3c12f |
- if (rc != RPMRC_OK)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc);
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- pos += size;
|
|
|
b3c12f |
+ while (next >= 0) {
|
|
|
b3c12f |
+ next = rpmfiNext(fi);
|
|
|
b3c12f |
+ if (next == RPMERR_ITER_END) {
|
|
|
b3c12f |
+ rc = RPMRC_OK;
|
|
|
b3c12f |
+ break;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ mode = rpmfiFMode(fi);
|
|
|
b3c12f |
+ if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) {
|
|
|
b3c12f |
+ /* not a regular file, or the archive doesn't contain any content
|
|
|
b3c12f |
+ * for this entry.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ continue;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ digest = rpmfiFDigest(fi, NULL, NULL);
|
|
|
b3c12f |
+ if (digestSetGetEntry(ds, digest, NULL)) {
|
|
|
b3c12f |
+ /* This specific digest has already been included, so skip it. */
|
|
|
b3c12f |
+ continue;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ pad = pad_to(pos, fundamental_block_size);
|
|
|
b3c12f |
+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write padding\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ /* round up to next fundamental_block_size */
|
|
|
b3c12f |
+ pos += pad;
|
|
|
b3c12f |
+ digestSetAddEntry(ds, digest);
|
|
|
b3c12f |
+ offsets[offset_ix].digest = digest;
|
|
|
b3c12f |
+ offsets[offset_ix].pos = pos;
|
|
|
b3c12f |
+ offset_ix++;
|
|
|
b3c12f |
+ size = rpmfiFSize(fi);
|
|
|
b3c12f |
+ rc = rpmfiArchiveReadToFile(fi, fdo, 0);
|
|
|
b3c12f |
+ if (rc != RPMRC_OK) {
|
|
|
b3c12f |
+ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc);
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ pos += size;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
Fclose(gzdi); /* XXX gzdi == fdi */
|
|
|
b3c12f |
|
|
|
b3c12f |
- qsort(
|
|
|
b3c12f |
- offsets,
|
|
|
b3c12f |
- (size_t)offset_ix,
|
|
|
b3c12f |
- sizeof(struct digestoffset),
|
|
|
b3c12f |
- digestoffsetCmp
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
+ qsort(offsets, (size_t)offset_ix, sizeof(struct digestoffset),
|
|
|
b3c12f |
+ digestoffsetCmp);
|
|
|
b3c12f |
|
|
|
b3c12f |
len = sizeof(offset_ix);
|
|
|
b3c12f |
- if (Fwrite(&offset_ix, len, 1, fdo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write length of table\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (Fwrite(&offset_ix, len, 1, fdo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write length of table\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
len = sizeof(diglen);
|
|
|
b3c12f |
- if (Fwrite(&diglen, len, 1, fdo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write length of digest\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (Fwrite(&diglen, len, 1, fdo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write length of digest\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
len = sizeof(rpm_loff_t);
|
|
|
b3c12f |
- for (int x = 0; x < offset_ix; x++)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write digest\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- if (Fwrite(&offsets[x].pos, len, 1, fdo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write offset\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
+ for (int x = 0; x < offset_ix; x++) {
|
|
|
b3c12f |
+ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write digest\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write offset\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
}
|
|
|
b3c12f |
validation_pos = (
|
|
|
b3c12f |
- pos + sizeof(offset_ix) + sizeof(diglen) +
|
|
|
b3c12f |
- offset_ix * (diglen + sizeof(rpm_loff_t))
|
|
|
b3c12f |
+ pos + sizeof(offset_ix) + sizeof(diglen) +
|
|
|
b3c12f |
+ offset_ix * (diglen + sizeof(rpm_loff_t))
|
|
|
b3c12f |
);
|
|
|
b3c12f |
|
|
|
b3c12f |
ssize_t validation_len = ufdCopy(validationi, fdo);
|
|
|
b3c12f |
- if (validation_len == -1)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("digest table ufdCopy failed\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (validation_len == -1) {
|
|
|
b3c12f |
+ fprintf(stderr, _("digest table ufdCopy failed\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
/* add more padding so the last file can be cloned. It doesn't matter that
|
|
|
b3c12f |
- the table and validation etc are in this space. In fact, it's pretty
|
|
|
b3c12f |
- efficient if it is
|
|
|
b3c12f |
+ * the table and validation etc are in this space. In fact, it's pretty
|
|
|
b3c12f |
+ * efficient if it is.
|
|
|
b3c12f |
*/
|
|
|
b3c12f |
|
|
|
b3c12f |
- pad = pad_to(
|
|
|
b3c12f |
- (
|
|
|
b3c12f |
- validation_pos + validation_len + 2 * sizeof(rpm_loff_t) +
|
|
|
b3c12f |
- sizeof(uint64_t)
|
|
|
b3c12f |
- ),
|
|
|
b3c12f |
- fundamental_block_size
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- if (Fwrite(zeros, sizeof(char), pad, fdo) != pad)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write final padding\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ pad = pad_to((validation_pos + validation_len + 2 * sizeof(rpm_loff_t) +
|
|
|
b3c12f |
+ sizeof(uint64_t)), fundamental_block_size);
|
|
|
b3c12f |
+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write final padding\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
zeros = _free(zeros);
|
|
|
b3c12f |
- if (Fwrite(&pos, len, 1, fdo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write offset of digest table\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (Fwrite(&pos, len, 1, fdo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write offset of digest table\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
- if (Fwrite(&validation_pos, len, 1, fdo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write offset of validation table\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (Fwrite(&validation_pos, len, 1, fdo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write offset of validation table\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
uint64_t magic = MAGIC;
|
|
|
b3c12f |
len = sizeof(magic);
|
|
|
b3c12f |
- if (Fwrite(&magic, len, 1, fdo) != len)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Unable to write magic\n"));
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- goto exit;
|
|
|
b3c12f |
+ if (Fwrite(&magic, len, 1, fdo) != len) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Unable to write magic\n"));
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ goto exit;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
exit:
|
|
|
b3c12f |
@@ -389,8 +327,7 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
|
|
|
b3c12f |
return rc;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
-int main(int argc, char *argv[])
|
|
|
b3c12f |
-{
|
|
|
b3c12f |
+int main(int argc, char *argv[]) {
|
|
|
b3c12f |
rpmRC rc;
|
|
|
b3c12f |
int cprc = 0;
|
|
|
b3c12f |
uint8_t algos[argc - 1];
|
|
|
b3c12f |
@@ -402,118 +339,95 @@ int main(int argc, char *argv[])
|
|
|
b3c12f |
xsetprogname(argv[0]); /* Portability call -- see system.h */
|
|
|
b3c12f |
rpmReadConfigFiles(NULL, NULL);
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]);
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]);
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (argc == 1)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (argc == 1) {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n"));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
- for (int x = 0; x < (argc - 1); x++)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Unable to resolve '%s' as a digest algorithm, exiting\n"),
|
|
|
b3c12f |
- argv[x + 1]
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
+ for (int x = 0; x < (argc - 1); x++) {
|
|
|
b3c12f |
+ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0)
|
|
|
b3c12f |
+ {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"),
|
|
|
b3c12f |
+ argv[x + 1]);
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
|
|
|
b3c12f |
- if (pipe(mainpipefd) == -1)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Main pipe failure\n"));
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (pipe(mainpipefd) == -1) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Main pipe failure\n"));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
- if (pipe(metapipefd) == -1)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("Meta pipe failure\n"));
|
|
|
b3c12f |
- exit(EXIT_FAILURE);
|
|
|
b3c12f |
+ if (pipe(metapipefd) == -1) {
|
|
|
b3c12f |
+ fprintf(stderr, _("Meta pipe failure\n"));
|
|
|
b3c12f |
+ exit(EXIT_FAILURE);
|
|
|
b3c12f |
}
|
|
|
b3c12f |
cpid = fork();
|
|
|
b3c12f |
- if (cpid == 0)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- /* child: digestor */
|
|
|
b3c12f |
- close(mainpipefd[0]);
|
|
|
b3c12f |
- close(metapipefd[0]);
|
|
|
b3c12f |
- FD_t fdi = fdDup(STDIN_FILENO);
|
|
|
b3c12f |
- FD_t fdo = fdDup(mainpipefd[1]);
|
|
|
b3c12f |
- FD_t validationo = fdDup(metapipefd[1]);
|
|
|
b3c12f |
- rc = digestor(fdi, fdo, validationo, algos, argc - 1);
|
|
|
b3c12f |
- Fclose(validationo);
|
|
|
b3c12f |
- Fclose(fdo);
|
|
|
b3c12f |
- Fclose(fdi);
|
|
|
b3c12f |
+ if (cpid == 0) {
|
|
|
b3c12f |
+ /* child: digestor */
|
|
|
b3c12f |
+ close(mainpipefd[0]);
|
|
|
b3c12f |
+ close(metapipefd[0]);
|
|
|
b3c12f |
+ FD_t fdi = fdDup(STDIN_FILENO);
|
|
|
b3c12f |
+ FD_t fdo = fdDup(mainpipefd[1]);
|
|
|
b3c12f |
+ FD_t validationo = fdDup(metapipefd[1]);
|
|
|
b3c12f |
+ rc = digestor(fdi, fdo, validationo, algos, argc - 1);
|
|
|
b3c12f |
+ Fclose(validationo);
|
|
|
b3c12f |
+ Fclose(fdo);
|
|
|
b3c12f |
+ Fclose(fdi);
|
|
|
b3c12f |
} else {
|
|
|
b3c12f |
- /* parent: main program */
|
|
|
b3c12f |
- close(mainpipefd[1]);
|
|
|
b3c12f |
- close(metapipefd[1]);
|
|
|
b3c12f |
- FD_t fdi = fdDup(mainpipefd[0]);
|
|
|
b3c12f |
- FD_t validationi = fdDup(metapipefd[0]);
|
|
|
b3c12f |
- rc = process_package(fdi, validationi);
|
|
|
b3c12f |
- Fclose(validationi);
|
|
|
b3c12f |
- /* fdi is normally closed through the stacked file gzdi in the function. */
|
|
|
b3c12f |
- /* wait for child process (digestor for stdin) to complete. */
|
|
|
b3c12f |
- if (rc != RPMRC_OK)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- if (kill(cpid, SIGTERM) != 0)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Failed to kill digest process when main process failed: %s\n"),
|
|
|
b3c12f |
- strerror(errno)
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- w = waitpid(cpid, &wstatus, 0);
|
|
|
b3c12f |
- if (w == -1)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(stderr, _("waitpid failed\n"));
|
|
|
b3c12f |
- cprc = EXIT_FAILURE;
|
|
|
b3c12f |
- } else if (WIFEXITED(wstatus))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- cprc = WEXITSTATUS(wstatus);
|
|
|
b3c12f |
- if (cprc != 0)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Digest process non-zero exit code %d\n"),
|
|
|
b3c12f |
- cprc
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- } else if (WIFSIGNALED(wstatus))
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- fprintf(
|
|
|
b3c12f |
- stderr,
|
|
|
b3c12f |
- _("Digest process was terminated with a signal: %d\n"),
|
|
|
b3c12f |
- WTERMSIG(wstatus)
|
|
|
b3c12f |
- );
|
|
|
b3c12f |
- cprc = EXIT_FAILURE;
|
|
|
b3c12f |
- } else
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- /* don't think this can happen, but covering all bases */
|
|
|
b3c12f |
- fprintf(stderr, _("Unhandled circumstance in waitpid\n"));
|
|
|
b3c12f |
- cprc = EXIT_FAILURE;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
- if (cprc != EXIT_SUCCESS)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- rc = RPMRC_FAIL;
|
|
|
b3c12f |
- }
|
|
|
b3c12f |
+ /* parent: main program */
|
|
|
b3c12f |
+ close(mainpipefd[1]);
|
|
|
b3c12f |
+ close(metapipefd[1]);
|
|
|
b3c12f |
+ FD_t fdi = fdDup(mainpipefd[0]);
|
|
|
b3c12f |
+ FD_t validationi = fdDup(metapipefd[0]);
|
|
|
b3c12f |
+ rc = process_package(fdi, validationi);
|
|
|
b3c12f |
+ Fclose(validationi);
|
|
|
b3c12f |
+ /* fdi is normally closed through the stacked file gzdi in the
|
|
|
b3c12f |
+ * function.
|
|
|
b3c12f |
+ * Wait for child process (digestor for stdin) to complete.
|
|
|
b3c12f |
+ */
|
|
|
b3c12f |
+ if (rc != RPMRC_OK) {
|
|
|
b3c12f |
+ if (kill(cpid, SIGTERM) != 0) {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Failed to kill digest process when main process failed: %s\n"),
|
|
|
b3c12f |
+ strerror(errno));
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ w = waitpid(cpid, &wstatus, 0);
|
|
|
b3c12f |
+ if (w == -1) {
|
|
|
b3c12f |
+ fprintf(stderr, _("waitpid failed\n"));
|
|
|
b3c12f |
+ cprc = EXIT_FAILURE;
|
|
|
b3c12f |
+ } else if (WIFEXITED(wstatus)) {
|
|
|
b3c12f |
+ cprc = WEXITSTATUS(wstatus);
|
|
|
b3c12f |
+ if (cprc != 0) {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Digest process non-zero exit code %d\n"),
|
|
|
b3c12f |
+ cprc);
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ } else if (WIFSIGNALED(wstatus)) {
|
|
|
b3c12f |
+ fprintf(stderr,
|
|
|
b3c12f |
+ _("Digest process was terminated with a signal: %d\n"),
|
|
|
b3c12f |
+ WTERMSIG(wstatus));
|
|
|
b3c12f |
+ cprc = EXIT_FAILURE;
|
|
|
b3c12f |
+ } else {
|
|
|
b3c12f |
+ /* Don't think this can happen, but covering all bases */
|
|
|
b3c12f |
+ fprintf(stderr, _("Unhandled circumstance in waitpid\n"));
|
|
|
b3c12f |
+ cprc = EXIT_FAILURE;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
+ if (cprc != EXIT_SUCCESS) {
|
|
|
b3c12f |
+ rc = RPMRC_FAIL;
|
|
|
b3c12f |
+ }
|
|
|
b3c12f |
}
|
|
|
b3c12f |
- if (rc != RPMRC_OK)
|
|
|
b3c12f |
- {
|
|
|
b3c12f |
- /* translate rpmRC into generic failure return code. */
|
|
|
b3c12f |
- return EXIT_FAILURE;
|
|
|
b3c12f |
+ if (rc != RPMRC_OK) {
|
|
|
b3c12f |
+ /* translate rpmRC into generic failure return code. */
|
|
|
b3c12f |
+ return EXIT_FAILURE;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
return EXIT_SUCCESS;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
|
|
|
b3c12f |
From 19694b76508d83bc83201441ff2c2721d45c4d1d Mon Sep 17 00:00:00 2001
|
|
|
b3c12f |
From: Matthew Almond <malmond@fb.com>
|
|
|
b3c12f |
Date: Sun, 31 Jan 2021 15:24:25 -0800
|
|
|
b3c12f |
Subject: [PATCH 4/4] Fix printf formatting in reflink.c
|
|
|
b3c12f |
|
|
|
b3c12f |
There were some mismatches on field "sizes". This should eliminate the
|
|
|
b3c12f |
error messages.
|
|
|
b3c12f |
---
|
|
|
b3c12f |
plugins/reflink.c | 2 +-
|
|
|
b3c12f |
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
b3c12f |
|
|
|
b3c12f |
diff --git a/plugins/reflink.c b/plugins/reflink.c
|
|
|
b3c12f |
index 9eaa87094..513887604 100644
|
|
|
b3c12f |
--- a/plugins/reflink.c
|
|
|
b3c12f |
+++ b/plugins/reflink.c
|
|
|
b3c12f |
@@ -316,7 +316,7 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path,
|
|
|
b3c12f |
return RPMRC_FAIL;
|
|
|
b3c12f |
}
|
|
|
b3c12f |
rpmlog(RPMLOG_DEBUG,
|
|
|
b3c12f |
- _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"),
|
|
|
b3c12f |
+ _("reflink: Reflinking %llu bytes at %llu to %s orig size=%ld, file=%lld\n"),
|
|
|
b3c12f |
fcr.src_length, fcr.src_offset, path, size, fcr.src_fd);
|
|
|
b3c12f |
rc = ioctl(dst, FICLONERANGE, &fcr;;
|
|
|
b3c12f |
if (rc) {
|