#include "libpspp/integer-format.h"
#include "libpspp/str.h"
+#include "gl/crc.h"
#include "gl/xalloc.h"
#include "gettext.h"
uint32_t offset; /* Starting offset in file. */
uint32_t comp_size; /* Length of member file data, in bytes. */
uint32_t ucomp_size; /* Uncompressed length of member file data, in bytes. */
+
+ uint32_t expected_crc;
+ uint32_t accumulated_crc;
+
const struct decompressor *decompressor;
size_t bytes_unread; /* Number of bytes left in the member available for reading */
uint32_t offset; /* Starting offset in file. */
uint32_t comp_size; /* Length of member file data, in bytes. */
uint32_t ucomp_size; /* Uncompressed length of member file data, in bytes. */
+ uint32_t expected_crc; /* CRC32 of uncompressed data. */
char *name; /* Name of member file. */
};
return 0;
int bytes_read = zm->decompressor->read (zm, buf, bytes);
- if (bytes_read < 0)
+ if (bytes_read <= 0)
return bytes_read;
zm->bytes_unread -= bytes_read;
+ zm->accumulated_crc = crc32_update (zm->accumulated_crc, buf, bytes_read);
+ if (!zm->bytes_unread && zm->accumulated_crc != zm->expected_crc)
+ {
+ zm->error = xasprintf (_("%s: corrupt archive reading member \"%s\": "
+ "bad CRC %#"PRIx32" (expected %"PRIx32")"),
+ zm->file_name, zm->member_name,
+ zm->accumulated_crc, zm->expected_crc);
+ return -1;
+ }
return bytes_read;
}
get_u16 (file); /* comp_type */
get_u16 (file); /* time */
get_u16 (file); /* date */
- get_u32 (file); /* expected_crc */
+ ze->expected_crc = get_u32 (file);
ze->comp_size = get_u32 (file);
ze->ucomp_size = get_u32 (file);
uint16_t nlen = get_u16 (file);
zr->file_name, strerror (errno));
struct zip_member *zm = xmalloc (sizeof *zm);
- zm->file_name = xstrdup (zr->file_name);
- zm->member_name = xstrdup (member);
- zm->fp = fp;
- zm->offset = ze->offset;
- zm->comp_size = ze->comp_size;
- zm->ucomp_size = ze->ucomp_size;
- zm->decompressor = NULL;
- zm->bytes_unread = ze->ucomp_size;
- zm->aux = NULL;
- zm->error = NULL;
+ *zm = (struct zip_member) {
+ .file_name = xstrdup (zr->file_name),
+ .member_name = xstrdup (member),
+ .fp = fp,
+ .offset = ze->offset,
+ .comp_size = ze->comp_size,
+ .ucomp_size = ze->ucomp_size,
+ .bytes_unread = ze->ucomp_size,
+ .expected_crc = ze->expected_crc,
+ };
char *error;
if (0 != fseeko (zm->fp, zm->offset, SEEK_SET))
])
AT_CLEANUP
+AT_SETUP([zip - detect corruption on unzip])
+AT_KEYWORDS([compression])
+mkdir write
+cd write
+AT_DATA([data.txt], [xyzzy
+])
+AT_CHECK([zip-test w ../foo.zip data.txt])
+cd ..
+
+mkdir extract
+cd extract
+AT_CHECK([zip-test r ../foo.zip data.txt])
+AT_CHECK([cat data.txt], [0], [xyzzy
+])
+cd ..
+
+mkdir error
+cd error
+sed 's/xyzzy/XYZZY/' < ../foo.zip > ../corrupted.zip
+AT_CHECK([zip-test r ../corrupted.zip data.txt], [1], [], [dnl
+Unzip failed: ../corrupted.zip: corrupt archive reading member "data.txt": bad CRC 0x2a2bcd20 (expected e1bd2a6e)
+])
+AT_CLEANUP
AT_SETUP([zip to pipe])
AT_KEYWORDS([compression])