summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/network/network_content.cpp39
1 files changed, 29 insertions, 10 deletions
diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp
index 042f4596d..c722fd585 100644
--- a/src/network/network_content.cpp
+++ b/src/network/network_content.cpp
@@ -373,19 +373,38 @@ static bool GunzipFile(const ContentInfo *ci)
if (fin == NULL || fout == NULL) {
ret = false;
- goto exit;
- }
-
- byte buff[8192];
- while (!gzeof(fin)) {
- int read = gzread(fin, buff, sizeof(buff));
- if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
- ret = false;
- break;
+ } else {
+ byte buff[8192];
+ while (1) {
+ int read = gzread(fin, buff, sizeof(buff));
+ if (read == 0) {
+ /* If gzread() returns 0, either the end-of-file has been
+ * reached or an underlying read error has occurred.
+ *
+ * gzeof() can't be used, because:
+ * 1.2.5 - it is safe, 1 means 'everything was OK'
+ * 1.2.3.5, 1.2.4 - 0 or 1 is returned 'randomly'
+ * 1.2.3.3 - 1 is returned for truncated archive
+ *
+ * So we use gzerror(). When proper end of archive
+ * has been reached, then:
+ * errnum == Z_STREAM_END in 1.2.3.3,
+ * errnum == 0 in 1.2.4 and 1.2.5 */
+ int errnum;
+ gzerror(fin, &errnum);
+ if (errnum != 0 && errnum != Z_STREAM_END) ret = false;
+ break;
+ }
+ if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
+ /* If gzread() returns -1, there was an error in archive */
+ ret = false;
+ break;
+ }
+ /* DO NOT DO THIS! It will fail to detect broken archive with 1.2.3.3!
+ * if (read < sizeof(buff)) break; */
}
}
-exit:
if (fin != NULL) {
/* Closes ftmp too! */
gzclose(fin);