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