A gzclose call has the same potential for errors as a write, since the compressor needs to flush its buffers before closing its output file. The same applies to BZ2_bzclose, but unfortunately libbz2's gzio-style API does not expose the error code. Luckily, the only possible errors are I/O errors, which can be detected through errno.
Similarly, explicitly closing a file descriptor can reveal errors writing out buffered data. Closing input handles, on the other hand, would be a waste of time: all it would accomplish is to free some resources held by a process that is about to exit anyway. Signed-off-by: Jonathan Nieder <[email protected]> --- lib/dpkg/compression-backend.c | 56 +++++++++++++++++++++++++++++++++++----- 1 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/dpkg/compression-backend.c b/lib/dpkg/compression-backend.c index 112b817..7a1e664 100644 --- a/lib/dpkg/compression-backend.c +++ b/lib/dpkg/compression-backend.c @@ -119,17 +119,22 @@ default_memlimit() ohshite(_("%s: internal " format " error: %s"), \ desc, "write"); \ } \ + \ + if (close(fd_out)) \ + ohshite(_("%s: internal " format " error: %s"), \ + desc, "close"); \ exit(0); \ } while(0) -#define COMPRESS(format, zFile, zdopen, zwrite, zclose, zerror, ERR_ERRNO, \ +#define COMPRESS(format, zFile, zdopen, zwrite, zclose, \ + zcloseerror, zerror, ERR_ERRNO, \ fd_in, fd_out, compression, desc) do \ { \ /* If compression == '\0', use library default. */ \ char combuf[] = {'w', compression, '\0'}; \ - int actualread, actualwrite; \ char buffer[DPKG_BUFFER_SIZE]; \ zFile zfile; \ + int actualread, actualwrite, err = 0; \ \ zfile = zdopen(fd_out, combuf); \ while ((actualread = read(fd_in, buffer, sizeof(buffer)))) { \ @@ -139,7 +144,6 @@ default_memlimit() \ actualwrite = zwrite(zfile, buffer, actualread); \ if (actualwrite != actualread) { \ - int err = 0; \ const char *errmsg = zerror(zfile, &err); \ \ if (err == ERR_ERRNO) \ @@ -148,7 +152,15 @@ default_memlimit() desc, "write", errmsg); \ } \ } \ - zclose(zfile); \ + \ + err = zclose(zfile); \ + if (err) { \ + const char *errmsg = err == ERR_ERRNO ? \ + strerror(errno) : zcloseerror(err); \ + \ + ohshit(_("%s: internal " format " error: %s: %s"), \ + desc, "close", errmsg); \ + } \ exit(0); \ } while(0) @@ -174,7 +186,8 @@ compress_gzip(int fd_in, int fd_out, char compression, const char *desc) if (compression == '\0') compression = default_gz_compression; - COMPRESS("gzip", gzFile, gzdopen, gzwrite, gzclose, gzerror, Z_ERRNO, + COMPRESS("gzip", gzFile, gzdopen, gzwrite, gzclose, + zError, gzerror, Z_ERRNO, fd_in, fd_out, compression, desc); } #else /* !WITH_ZLIB */ @@ -195,6 +208,35 @@ compress_gzip(int fd_in, int fd_out, char compression, const char *desc) #endif #ifdef WITH_BZ2 +/* + * BZ2_bzclose does not pass on the error code to the caller. + * To work around this, we could + * - set errno to 0 and compare the value afterwards, hoping + * that libbz2 did not recover from any errors itself + * or + * - modify a copy of BZ2_bzclose to expose the error + * This function follows the former course, so it can continue + * to work even if the layout of BZFILE objects should change. + */ +static int +bzclose(BZFILE *b) +{ + errno = 0; + bzclose(b); + if (errno) + return BZ_IO_ERROR; + + return 0; +} + +static const char *bzcloseerror(int err) DPKG_ATTR_CONST; +static const char * +bzcloseerror(int err) +{ + /* bzclose only returns BZ_OK and BZ_IO_ERROR. */ + return _("Unexpected error (bug)"); +} + void decompress_bzip2(int fd_in, int fd_out, const char *desc) { @@ -209,8 +251,8 @@ compress_bzip2(int fd_in, int fd_out, char compression, const char *desc) if (compression == '\0') compression = default_bz2_compression; - COMPRESS("bzip2", BZFILE *, BZ2_bzdopen, BZ2_bzwrite, BZ2_bzclose, - BZ2_bzerror, BZ_IO_ERROR, + COMPRESS("bzip2", BZFILE *, BZ2_bzdopen, BZ2_bzwrite, bzclose, + bzcloseerror, BZ2_bzerror, BZ_IO_ERROR, fd_in, fd_out, compression, desc); } #else /* !WITH_BZ2 */ -- 1.6.5.rc1.199.g596ec -- To UNSUBSCRIBE, email to [email protected] with a subject of "unsubscribe". Trouble? Contact [email protected]

