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.
This commit is contained in:
Panu Matilainen 2012-10-30 11:36:56 +02:00
parent 0b9c93ed18
commit cbd6ef58bb
5 changed files with 39 additions and 9 deletions

View File

@ -964,7 +964,7 @@ Header headerRead(FD_t fd, int magicp)
if (magicp == HEADER_MAGIC_YES) { if (magicp == HEADER_MAGIC_YES) {
int32_t magic; 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; goto exit;
magic = block[0]; magic = block[0];
@ -975,7 +975,7 @@ Header headerRead(FD_t fd, int magicp)
il = ntohl(block[2]); il = ntohl(block[2]);
dl = ntohl(block[3]); dl = ntohl(block[3]);
} else { } else {
if (Fread(block, 1, 2*sizeof(*block), fd) != 2*sizeof(*block)) if (Freadall(fd, block, 2*sizeof(*block)) != 2*sizeof(*block))
goto exit; goto exit;
il = ntohl(block[0]); il = ntohl(block[0]);
@ -993,7 +993,7 @@ Header headerRead(FD_t fd, int magicp)
ei[0] = htonl(il); ei[0] = htonl(il);
ei[1] = htonl(dl); ei[1] = htonl(dl);
if (Fread((char *)&ei[2], 1, blen, fd) != blen) if (Freadall(fd, (char *)&ei[2], blen) != blen)
goto exit; goto exit;
h = headerImport(ei, len, 0); h = headerImport(ei, len, 0);
@ -1747,3 +1747,29 @@ void headerSetInstance(Header h, unsigned int instance)
h->instance = 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;
}

View File

@ -72,6 +72,9 @@ extern "C" {
RPM_GNUC_INTERNAL RPM_GNUC_INTERNAL
void headerSetInstance(Header h, unsigned int instance); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -422,7 +422,7 @@ static rpmRC rpmpkgReadHeader(rpmKeyring keyring, rpmVSFlags vsflags,
*msg = NULL; *msg = NULL;
memset(block, 0, sizeof(block)); 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, rasprintf(&buf,
_("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx); _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
goto exit; goto exit;
@ -448,7 +448,7 @@ static rpmRC rpmpkgReadHeader(rpmKeyring keyring, rpmVSFlags vsflags,
ei = xmalloc(uc); ei = xmalloc(uc);
ei[0] = block[2]; ei[0] = block[2];
ei[1] = block[3]; 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); rasprintf(&buf, _("hdr blob(%zd): BAD, read returned %d\n"), nb, xx);
goto exit; goto exit;
} }

View File

@ -12,6 +12,7 @@
#include <rpm/rpmstring.h> #include <rpm/rpmstring.h>
#include "lib/signature.h" #include "lib/signature.h"
#include "lib/header_internal.h" /* Freadall() */
#include "lib/rpmlead.h" #include "lib/rpmlead.h"
#include "debug.h" #include "debug.h"
@ -117,7 +118,7 @@ rpmRC rpmLeadRead(FD_t fd, rpmlead *lead, int *type, char **emsg)
char *err = NULL; char *err = NULL;
memset(&l, 0, sizeof(l)); 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)) { if (Ferror(fd)) {
rasprintf(&err, _("read failed: %s (%d)\n"), Fstrerror(fd), errno); rasprintf(&err, _("read failed: %s (%d)\n"), Fstrerror(fd), errno);
rc = RPMRC_FAIL; rc = RPMRC_FAIL;

View File

@ -86,7 +86,7 @@ rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
goto exit; goto exit;
memset(block, 0, sizeof(block)); 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"), rasprintf(&buf, _("sigh size(%d): BAD, read returned %d\n"),
(int)sizeof(block), xx); (int)sizeof(block), xx);
goto exit; goto exit;
@ -118,7 +118,7 @@ rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
ei[1] = block[3]; ei[1] = block[3];
pe = (entryInfo) &ei[2]; pe = (entryInfo) &ei[2];
dataStart = (unsigned char *) (pe + il); dataStart = (unsigned char *) (pe + il);
if ((xx = Fread(pe, 1, nb, fd)) != nb) { if ((xx = Freadall(fd, pe, nb)) != nb) {
rasprintf(&buf, rasprintf(&buf,
_("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx); _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx);
goto exit; goto exit;
@ -214,7 +214,7 @@ rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, char ** msg)
rpm_loff_t archSize = 0; rpm_loff_t archSize = 0;
/* Position at beginning of header. */ /* Position at beginning of header. */
if (pad && (trc = Fread(block, 1, pad, fd)) != pad) { if (pad && (trc = Freadall(fd, block, pad)) != pad) {
rasprintf(&buf, rasprintf(&buf,
_("sigh pad(%zd): BAD, read %zd bytes\n"), pad, trc); _("sigh pad(%zd): BAD, read %zd bytes\n"), pad, trc);
goto exit; goto exit;