AmendHub

Download:

jcs

/

subtext

/

amendments

/

455

zip: Make zip_read_file return an error code depending on failure

This way the caller can differentiate between a temporary malloc
failure and a permanent "this zip file is busted".

jcs made amendment 455 about 1 year ago
--- zip.c Wed Mar 15 14:00:22 2023 +++ zip.c Mon Mar 27 16:45:53 2023 @@ -42,12 +42,15 @@ zip_read(short frefnum, void *buf, size_t len) error = FSRead(frefnum, &rlen, buf); if (error) { - warn("error reading zip: %d", frefnum); + logger_printf("[zip] error reading zip: %d", error); + if (error != eofErr) + warn("error reading zip: %d", error); return 0; } - if (rlen != len) - warn("short read on zip: got %ld wanted %ld", rlen, len); - + if (rlen != len) { + logger_printf("[zip] short read: got %ld wanted %ld", rlen, len); + return 0; + } return rlen; } @@ -75,7 +78,7 @@ read_done: } -bool +short zip_read_file(Str255 path, zip_extract_decider *decider, zip_extract_processor *processor) { @@ -84,127 +87,167 @@ zip_read_file(Str255 path, zip_extract_decider *decide unsigned char *comp, *uncomp; unsigned long comp_len, uncomp_len; u_int16_t t, fn_len, ex_len; - short ret, error, frefnum; + short ret, fret, error, frefnum; error = FSOpen(path, 0, &frefnum); if (error) { warn("failed opening %s: %d", PtoCstr(path), error); CtoPstr(path); - return false; + return ZIP_FAILED_OPEN; } for (;;) { - if (zip_read(frefnum, &buf, 4) != 4) + fret = 0; + + if (zip_read(frefnum, &buf, 4) != 4) { + fret = ZIP_SHORT_READ; goto read_fail; + } if (memcmp(buf, &zip_dir_magic, 4) == 0) break; - if (memcmp(buf, &zip_file_magic, 4) != 0) + if (memcmp(buf, &zip_file_magic, 4) != 0) { + fret = ZIP_BAD_FILE; goto read_fail; - + } + /* version */ - if (zip_read(frefnum, &buf, 2) != 2) + if (zip_read(frefnum, &buf, 2) != 2) { + fret = ZIP_UNSUPPORTED; goto read_fail; + } /* flags */ - if (zip_read(frefnum, &buf, 2) != 2) + if (zip_read(frefnum, &buf, 2) != 2) { + fret = ZIP_SHORT_READ; goto read_fail; + } t = GET_U16(&buf); if (t & (1 << 0)) { logger_printf("[zip] Encryption not supported"); + fret = ZIP_UNSUPPORTED; goto read_fail; } /* compression */ - if (zip_read(frefnum, &buf, 2) != 2) + if (zip_read(frefnum, &buf, 2) != 2) { + fret = ZIP_SHORT_READ; goto read_fail; + } t = GET_U16(&buf); if (t != 8) { logger_printf("[zip] Compression method %d not supported", t); + fret = ZIP_UNSUPPORTED; goto read_fail; } /* mod time/date */ - if (zip_read(frefnum, &buf, 4) != 4) + if (zip_read(frefnum, &buf, 4) != 4) { + fret = ZIP_SHORT_READ; goto read_fail; - + } + /* crc32 */ - if (zip_read(frefnum, &buf, 4) != 4) + if (zip_read(frefnum, &buf, 4) != 4) { + fret = ZIP_SHORT_READ; goto read_fail; + } /* compressed size */ - if (zip_read(frefnum, &buf, 4) != 4) + if (zip_read(frefnum, &buf, 4) != 4) { + fret = ZIP_SHORT_READ; goto read_fail; + } comp_len = GET_U32(&buf); if (comp_len == 0xffffffff) { logger_printf("[zip] ZIP64 not supported"); + fret = ZIP_UNSUPPORTED; goto read_fail; } if ((signed long)comp_len < 0) { logger_printf("[zip] Bogus compressed length (%lu)", comp_len); + fret = ZIP_BAD_FILE; goto read_fail; } if (comp_len == 0) { logger_printf("[zip] Data descriptor not supported"); + fret = ZIP_UNSUPPORTED; goto read_fail; } /* uncompressed size */ - if (zip_read(frefnum, &buf, 4) != 4) + if (zip_read(frefnum, &buf, 4) != 4) { + fret = ZIP_SHORT_READ; goto read_fail; + } uncomp_len = GET_U32(&buf); if (uncomp_len == 0xffffffff) { logger_printf("[zip] ZIP64 not supported"); + fret = ZIP_UNSUPPORTED; goto read_fail; } if ((signed long)uncomp_len < 0) { logger_printf("[zip] Bogus uncompressed length (%lu)", uncomp_len); + fret = ZIP_BAD_FILE; goto read_fail; } if (uncomp_len == 0) { logger_printf("[zip] Data descriptor not supported"); + fret = ZIP_UNSUPPORTED; goto read_fail; } /* file name len */ - if (zip_read(frefnum, &buf, 2) != 2) + if (zip_read(frefnum, &buf, 2) != 2) { + fret = ZIP_SHORT_READ; goto read_fail; + } fn_len = GET_U16(&buf); if (fn_len >= sizeof(buf)) { logger_printf("[zip] Filename len %d too big", fn_len); + fret = ZIP_UNSUPPORTED; goto read_fail; } /* extra field len */ - if (zip_read(frefnum, &buf, 2) != 2) + if (zip_read(frefnum, &buf, 2) != 2) { + fret = ZIP_SHORT_READ; goto read_fail; + } ex_len = GET_U16(&buf); /* filename */ if (fn_len > sizeof(filename)) { logger_printf("[zip] Filename too long (%ld)", fn_len); + fret = ZIP_UNSUPPORTED; goto read_fail; } - if (zip_read(frefnum, &filename, fn_len) != fn_len) + if (zip_read(frefnum, &filename, fn_len) != fn_len) { + fret = ZIP_SHORT_READ; goto read_fail; + } filename[fn_len] = '\0'; /* extra field */ - if (zip_read(frefnum, &buf, ex_len) != ex_len) + if (zip_read(frefnum, &buf, ex_len) != ex_len) { + fret = ZIP_SHORT_READ; goto read_fail; - + } + if (decider(filename, uncomp_len)) { comp = xmalloc(comp_len); if (comp == NULL) { logger_printf("[zip] Failed to malloc(%ld) for " "compressed data", comp_len); + fret = ZIP_NO_MEMORY; goto read_fail; } /* read compressed data */ if (zip_read(frefnum, comp, comp_len) != comp_len) { xfree(&comp); + fret = ZIP_SHORT_READ; goto read_fail; } @@ -212,6 +255,7 @@ zip_read_file(Str255 path, zip_extract_decider *decide if (uncomp == NULL) { logger_printf("[zip] Failed to malloc(%ld) for " "uncompressed data", uncomp_len); + fret = ZIP_NO_MEMORY; xfree(&comp); goto read_fail; } @@ -221,6 +265,7 @@ zip_read_file(Str255 path, zip_extract_decider *decide logger_printf("[zip] Unzip failed: %d", ret); xfree(&comp); xfree(&uncomp); + fret = ZIP_BAD_FILE; goto read_fail; } xfree(&comp); @@ -234,10 +279,12 @@ zip_read_file(Str255 path, zip_extract_decider *decide } FSClose(frefnum); - return true; + return ZIP_OK; read_fail: FSClose(frefnum); - return false; + if (fret == 0) + fret = ZIP_BAD_FILE; + return fret; } --- zip.h Mon Mar 6 15:42:42 2023 +++ zip.h Mon Mar 27 16:45:41 2023 @@ -37,12 +37,19 @@ ((unsigned char *)buf)[2] = ((i) >> 16) & 0xff; \ ((unsigned char *)buf)[3] = ((i) >> 24) & 0xff; +#define ZIP_OK 0 +#define ZIP_BAD_FILE -1 +#define ZIP_FAILED_OPEN -2 +#define ZIP_SHORT_READ -3 +#define ZIP_UNSUPPORTED -4 +#define ZIP_NO_MEMORY -10 + typedef bool zip_extract_decider(char *filename, size_t extracted_size); typedef void zip_extract_processor(char *filename, unsigned char *extracted_data, size_t extracted_size); bool zip_is_zip_file(Str255 path); -bool zip_read_file(Str255 path, zip_extract_decider *decider, +short zip_read_file(Str255 path, zip_extract_decider *decider, zip_extract_processor *processor); #endif