zlib 1.2.3.5 (and 1.2.4, although not yet packaged) breaks the openttd package due to gzeof misbehaving.
The manual states: "If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected." However, tests have shown that even when gzeof returns true, gzread has not returned all data yet. Actually checking the gzread function's return value to be <= 0 and then using gzeof to figure out whether it was an error or end-of-file works around the problem. As such I deduced that gzread returns data after gzeof returns true for the first time. In our case the output file is short "correct output file size" modulo 65536 bytes. As such gzeof of zlib 1.2.3.5 and 1.2.4 is unusable. I think wireshark's behaviour can be explained in a similar way: the seeking in the file causes zlib to read a number of bytes from the file and then it notices the end-of-file and sets some flag so gzeof returns 0. Note that this is pure speculation based on the description of the error and my experience with the behaviour in OpenTTD. Note that in 1.2.3.4 it did behave like the manual states. Attached is a simple program that shows the difference in behaviour between 1.2.3.4 and 1.2.3.5. g++ -lz -o gzeof_test gzeof_test.cpp # compile the test program dd if=/dev/zero of=test bs=100000 count=1 # create 100000 bytes file wc test # yes, it's 100000 bytes gzip test # compress that file ./gzeof_test test.gz test # uncompress with test program wc test # 100000 bytes with 1.2.3.4 # but 16384 bytes with 1.2.3.5 gunzip test.gz # yes, it's 100000 bytes, i.e. # test.gz is correct Regards, Remko Bijker
#include <stdlib.h> #include <stdio.h> #include <zlib.h> static bool GunzipFile(const char *filename_in, const char *filename_out) { bool ret = true; FILE *ftmp = fopen(filename_in, "rb"); gzFile fin = gzdopen(fileno(ftmp), "rb"); FILE *fout = fopen(filename_out, "wb"); if (fin == NULL || fout == NULL) { if (fin == NULL) printf("Could not open %s\n", filename_in); if (fout == NULL) printf("Could not open %s\n", filename_out); ret = false; goto exit; } char buff[8192]; while (!gzeof(fin)) { int read = gzread(fin, buff, sizeof(buff)); if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) { printf("Reading or writing failed\n"); ret = false; break; } } exit: if (fin != NULL) { /* Closes ftmp too! */ gzclose(fin); } else if (ftmp != NULL) { /* In case the gz stream was opened correctly this will * be closed by gzclose. */ fclose(ftmp); } if (fout != NULL) fclose(fout); return ret; } int main(int argc, char *argv[]) { if (argc != 3) { printf("usage: %s <filename_in> <filename_out>\n", argv[0]); return -1; } printf("Using zlib %s (compiled with %s)\n", zlibVersion(), ZLIB_VERSION); bool ret = GunzipFile(argv[1], argv[2]); printf("Extracting %s\n", ret ? "succeeded" : "failed"); return ret; }