summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2012-10-30 11:36:56 +0200
committerPanu Matilainen <pmatilai@redhat.com>2012-10-30 11:36:56 +0200
commitcbd6ef58bbc122e6adf2138679915bd3845d6756 (patch)
tree32f42aee0061090f2d5c48911c94031cd21ca8e9 /lib
parent0b9c93ed18a11818a2f3645431a338bdc3f1fc81 (diff)
downloadrpm-cbd6ef58bbc122e6adf2138679915bd3845d6756.tar.gz
rpm-cbd6ef58bbc122e6adf2138679915bd3845d6756.tar.bz2
rpm-cbd6ef58bbc122e6adf2138679915bd3845d6756.zip
Handle partial reads and errors in package IO (RhBug:802839, RhBug:580974)
- There are no guarantees Fread() will return all of the requested size: it can return partial data eg on signals and pipe descriptors. Introduce a helper function to handle this centrally for all package read IO, effectively reintroducing timedRead() but without the caveats: timedRead() did not work on compressed streams, did not handle eg EINTR correctly and while really being an internal helper, was exported in the API.
Diffstat (limited to 'lib')
-rw-r--r--lib/header.c32
-rw-r--r--lib/header_internal.h3
-rw-r--r--lib/package.c4
-rw-r--r--lib/rpmlead.c3
-rw-r--r--lib/signature.c6
5 files changed, 39 insertions, 9 deletions
diff --git a/lib/header.c b/lib/header.c
index 5d14bc1b3..5ad1b2950 100644
--- a/lib/header.c
+++ b/lib/header.c
@@ -964,7 +964,7 @@ Header headerRead(FD_t fd, int magicp)
if (magicp == HEADER_MAGIC_YES) {
int32_t magic;
- if (Fread(block, 1, 4*sizeof(*block), fd) != 4*sizeof(*block))
+ if (Freadall(fd, block, 4*sizeof(*block)) != 4*sizeof(*block))
goto exit;
magic = block[0];
@@ -975,7 +975,7 @@ Header headerRead(FD_t fd, int magicp)
il = ntohl(block[2]);
dl = ntohl(block[3]);
} else {
- if (Fread(block, 1, 2*sizeof(*block), fd) != 2*sizeof(*block))
+ if (Freadall(fd, block, 2*sizeof(*block)) != 2*sizeof(*block))
goto exit;
il = ntohl(block[0]);
@@ -993,7 +993,7 @@ Header headerRead(FD_t fd, int magicp)
ei[0] = htonl(il);
ei[1] = htonl(dl);
- if (Fread((char *)&ei[2], 1, blen, fd) != blen)
+ if (Freadall(fd, (char *)&ei[2], blen) != blen)
goto exit;
h = headerImport(ei, len, 0);
@@ -1747,3 +1747,29 @@ void headerSetInstance(Header h, unsigned int instance)
h->instance = instance;
}
+#define RETRY_ERROR(_err) \
+ ((_err) == EINTR || (_err) == EAGAIN || (_err) == EWOULDBLOCK)
+
+ssize_t Freadall(FD_t fd, void * buf, ssize_t size)
+{
+ ssize_t total = 0;
+ ssize_t nb = 0;
+ char * bufp = buf;
+
+ while (total < size) {
+ nb = Fread(bufp, 1, size - total, fd);
+
+ if (nb == 0 || (nb < 0 && !RETRY_ERROR(errno))) {
+ total = nb;
+ break;
+ }
+
+ if (nb > 0) {
+ bufp += nb;
+ total += nb;
+ }
+ }
+
+ return total;
+}
+
diff --git a/lib/header_internal.h b/lib/header_internal.h
index 640071166..f51435fee 100644
--- a/lib/header_internal.h
+++ b/lib/header_internal.h
@@ -72,6 +72,9 @@ extern "C" {
RPM_GNUC_INTERNAL
void headerSetInstance(Header h, unsigned int instance);
+/* Package IO helper to consolidate partial read and error handling */
+RPM_GNUC_INTERNAL
+ssize_t Freadall(FD_t fd, void * buf, ssize_t size);
#ifdef __cplusplus
}
#endif
diff --git a/lib/package.c b/lib/package.c
index 6fb95a6da..9ce7130f9 100644
--- a/lib/package.c
+++ b/lib/package.c
@@ -422,7 +422,7 @@ static rpmRC rpmpkgReadHeader(rpmKeyring keyring, rpmVSFlags vsflags,
*msg = NULL;
memset(block, 0, sizeof(block));
- if ((xx = Fread(block, 1, sizeof(block), fd)) != sizeof(block)) {
+ if ((xx = Freadall(fd, block, sizeof(block))) != sizeof(block)) {
rasprintf(&buf,
_("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
goto exit;
@@ -448,7 +448,7 @@ static rpmRC rpmpkgReadHeader(rpmKeyring keyring, rpmVSFlags vsflags,
ei = xmalloc(uc);
ei[0] = block[2];
ei[1] = block[3];
- if ((xx = Fread((char *)&ei[2], 1, nb, fd)) != nb) {
+ if ((xx = Freadall(fd, (char *)&ei[2], nb)) != nb) {
rasprintf(&buf, _("hdr blob(%zd): BAD, read returned %d\n"), nb, xx);
goto exit;
}
diff --git a/lib/rpmlead.c b/lib/rpmlead.c
index 195c5f705..8e56bfc38 100644
--- a/lib/rpmlead.c
+++ b/lib/rpmlead.c
@@ -12,6 +12,7 @@
#include <rpm/rpmstring.h>
#include "lib/signature.h"
+#include "lib/header_internal.h" /* Freadall() */
#include "lib/rpmlead.h"
#include "debug.h"
@@ -117,7 +118,7 @@ rpmRC rpmLeadRead(FD_t fd, rpmlead *lead, int *type, char **emsg)
char *err = NULL;
memset(&l, 0, sizeof(l));
- if (Fread(&l, 1, sizeof(l), fd) != sizeof(l)) {
+ if (Freadall(fd, &l, sizeof(l)) != sizeof(l)) {
if (Ferror(fd)) {
rasprintf(&err, _("read failed: %s (%d)\n"), Fstrerror(fd), errno);
rc = RPMRC_FAIL;
diff --git a/lib/signature.c b/lib/signature.c
index c29064e8b..1c5327072 100644
--- a/lib/signature.c
+++ b/lib/signature.c
@@ -86,7 +86,7 @@ rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
goto exit;
memset(block, 0, sizeof(block));
- if ((xx = Fread(block, 1, sizeof(block), fd)) != sizeof(block)) {
+ if ((xx = Freadall(fd, block, sizeof(block))) != sizeof(block)) {
rasprintf(&buf, _("sigh size(%d): BAD, read returned %d\n"),
(int)sizeof(block), xx);
goto exit;
@@ -118,7 +118,7 @@ rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
ei[1] = block[3];
pe = (entryInfo) &ei[2];
dataStart = (unsigned char *) (pe + il);
- if ((xx = Fread(pe, 1, nb, fd)) != nb) {
+ if ((xx = Freadall(fd, pe, nb)) != nb) {
rasprintf(&buf,
_("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx);
goto exit;
@@ -214,7 +214,7 @@ rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
rpm_loff_t archSize = 0;
/* Position at beginning of header. */
- if (pad && (trc = Fread(block, 1, pad, fd)) != pad) {
+ if (pad && (trc = Freadall(fd, block, pad)) != pad) {
rasprintf(&buf,
_("sigh pad(%zd): BAD, read %zd bytes\n"), pad, trc);
goto exit;