diff options
author | Panu Matilainen <pmatilai@redhat.com> | 2012-10-30 11:36:56 +0200 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2012-10-30 11:36:56 +0200 |
commit | cbd6ef58bbc122e6adf2138679915bd3845d6756 (patch) | |
tree | 32f42aee0061090f2d5c48911c94031cd21ca8e9 /lib | |
parent | 0b9c93ed18a11818a2f3645431a338bdc3f1fc81 (diff) | |
download | rpm-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.c | 32 | ||||
-rw-r--r-- | lib/header_internal.h | 3 | ||||
-rw-r--r-- | lib/package.c | 4 | ||||
-rw-r--r-- | lib/rpmlead.c | 3 | ||||
-rw-r--r-- | lib/signature.c | 6 |
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; |