diff --git a/main.c b/main.c index 766007c..e0a0dcf 100644 --- a/main.c +++ b/main.c @@ -53,6 +53,7 @@ static void usage(void) print_output(" -t test compressed file integrity\n"); print_output(" -i show compressed file information\n"); print_output(" -H display md5 Hash integrity information\n"); + print_output(" -c check integrity of file written on decompression\n"); print_output("\nIf no filenames or \"-\" is specified, stdin/out will be used.\n"); } @@ -605,7 +606,7 @@ int main(int argc, char *argv[]) else if (!strstr(eptr,"NOCONFIG")) read_config(&control); - while ((c = getopt(argc, argv, "L:hdS:tVvDfqo:w:nlbMUO:T:N:p:gziH")) != -1) { + while ((c = getopt(argc, argv, "L:hdS:tVvDfqo:w:nlbMUO:T:N:p:gziHc")) != -1) { switch (c) { case 'L': control.compression_level = atoi(optarg); @@ -722,6 +723,10 @@ int main(int argc, char *argv[]) case 'H': control.flags |= FLAG_HASH; break; + case 'c': + control.flags |= FLAG_CHECK; + control.flags |= FLAG_HASH; + break; case 'h': usage(); return -1; @@ -747,6 +752,9 @@ int main(int argc, char *argv[]) control.flags &= ~ FLAG_UNLIMITED; } + if (CHECK_FILE && (!DECOMPRESS || !TEST_ONLY)) + print_err("Can only check file written on decompression or testing.\n"); + /* OK, if verbosity set, print summary of options selected */ if (!INFO) { if (!TEST_ONLY) diff --git a/runzip.c b/runzip.c index 98568a0..8fa5d69 100644 --- a/runzip.c +++ b/runzip.c @@ -276,6 +276,35 @@ i64 runzip_fd(int fd_in, int fd_out, int fd_hist, i64 expected_size) print_output("%02x", md5_resblock[i] & 0xFF); print_output("\n"); } + + if (CHECK_FILE) { + FILE *md5_fstream; + int i, j; + + memcpy(md5_stored, md5_resblock, MD5_DIGEST_SIZE); + if (unlikely(lseek(fd_out, 0, SEEK_SET) == -1)) + fatal("Failed to lseek fd_out in runzip_fd\n"); + if (unlikely((md5_fstream = fdopen(fd_out, "r")) == NULL)) + fatal("Failed to fdopen fd_out in runzip_fd\n"); + if (unlikely(md5_stream(md5_fstream, md5_resblock))) + fatal("Failed to md5_stream in runzip_fd\n"); + /* We dont' close the file here as it's closed in main */ + for (i = 0; i < MD5_DIGEST_SIZE; i++) + if (md5_stored[i] != md5_resblock[i]) { + print_output("MD5 CHECK FAILED.\nStored:"); + for (j = 0; j < MD5_DIGEST_SIZE; j++) + print_output("%02x", md5_stored[j] & 0xFF); + print_output("\nOutput file:"); + for (j = 0; j < MD5_DIGEST_SIZE; j++) + print_output("%02x", md5_resblock[j] & 0xFF); + fatal("\n"); + } + print_output("MD5 integrity of written file matches archive\n"); + if (!HAS_MD5) + print_output("Note this lrzip archive did not have a stored md5 value.\n" + "The archive decompression was validated with crc32 and the md5 hash was " + "calculated on decompression\n"); + } } return total; diff --git a/rzip.h b/rzip.h index f3096c3..3862a5b 100644 --- a/rzip.h +++ b/rzip.h @@ -214,6 +214,7 @@ static inline i64 get_ram(void) #define FLAG_UNLIMITED (1 << 16) #define FLAG_HASH (1 << 17) #define FLAG_MD5 (1 << 18) +#define FLAG_CHECK (1 << 19) #define FLAG_VERBOSE (FLAG_VERBOSITY | FLAG_VERBOSITY_MAX) #define FLAG_NOT_LZMA (FLAG_NO_COMPRESS | FLAG_LZO_COMPRESS | FLAG_BZIP2_COMPRESS | FLAG_ZLIB_COMPRESS | FLAG_ZPAQ_COMPRESS) @@ -239,6 +240,7 @@ static inline i64 get_ram(void) #define UNLIMITED (control.flags & FLAG_UNLIMITED) #define HASH_CHECK (control.flags & FLAG_HASH) #define HAS_MD5 (control.flags & FLAG_MD5) +#define CHECK_FILE (control.flags & FLAG_CHECK) #define NO_MD5 (!(HASH_CHECK) && !(HAS_MD5))