EXPORTED int gzuc_skip(struct gzuncat *gz, size_t len) { if (gzuc_member_eof(gz)) return -1; while (len) { unsigned char discard[16 * 1024]; size_t want = len; if (want > sizeof(discard)) want = sizeof(discard); ssize_t got = gzuc_read(gz, discard, want); if (got == 0) return -1; if (got < 0) return got; len -= got; } return 0; }
static int verify_chunk_checksums(struct backup *backup, struct backup_chunk *chunk, struct gzuncat *gzuc, int verbose, FILE *out) { int r; if (out && verbose) fprintf(out, "checking chunk %d checksums...\n", chunk->id); /* validate file-prior-to-this-chunk checksum */ if (out && verbose > 1) fprintf(out, " checking file checksum...\n"); char file_sha1[2 * SHA1_DIGEST_LENGTH + 1]; sha1_file(backup->fd, backup->data_fname, chunk->offset, file_sha1); r = strncmp(chunk->file_sha1, file_sha1, sizeof(file_sha1)); if (r) { syslog(LOG_DEBUG, "%s: %s (chunk %d) file checksum mismatch: %s on disk, %s in index\n", __func__, backup->data_fname, chunk->id, file_sha1, chunk->file_sha1); if (out) fprintf(out, "file checksum mismatch for chunk %d: %s on disk, %s in index\n", chunk->id, file_sha1, chunk->file_sha1); goto done; } /* validate data-within-this-chunk checksum */ // FIXME length and data_sha1 are set at backup_append_end. // detect and correctly report case where this hasn't occurred. if (out && verbose > 1) fprintf(out, " checking data length\n"); char buf[8192]; /* FIXME whatever */ size_t len = 0; SHA_CTX sha_ctx; SHA1_Init(&sha_ctx); gzuc_member_start_from(gzuc, chunk->offset); while (!gzuc_member_eof(gzuc)) { ssize_t n = gzuc_read(gzuc, buf, sizeof(buf)); if (n >= 0) { SHA1_Update(&sha_ctx, buf, n); len += n; } } gzuc_member_end(gzuc, NULL); if (len != chunk->length) { syslog(LOG_DEBUG, "%s: %s (chunk %d) data length mismatch: " SIZE_T_FMT " on disk," SIZE_T_FMT " in index\n", __func__, backup->data_fname, chunk->id, len, chunk->length); if (out) fprintf(out, "data length mismatch for chunk %d: " SIZE_T_FMT " on disk," SIZE_T_FMT " in index\n", chunk->id, len, chunk->length); r = -1; goto done; } if (out && verbose > 1) fprintf(out, " checking data checksum...\n"); unsigned char sha1_raw[SHA1_DIGEST_LENGTH]; char data_sha1[2 * SHA1_DIGEST_LENGTH + 1]; SHA1_Final(sha1_raw, &sha_ctx); r = bin_to_hex(sha1_raw, SHA1_DIGEST_LENGTH, data_sha1, BH_LOWER); assert(r == 2 * SHA1_DIGEST_LENGTH); r = strncmp(chunk->data_sha1, data_sha1, sizeof(data_sha1)); if (r) { syslog(LOG_DEBUG, "%s: %s (chunk %d) data checksum mismatch: %s on disk, %s in index\n", __func__, backup->data_fname, chunk->id, data_sha1, chunk->data_sha1); if (out) fprintf(out, "data checksum mismatch for chunk %d: %s on disk, %s in index\n", chunk->id, data_sha1, chunk->data_sha1); goto done; } done: syslog(LOG_DEBUG, "%s: checksum %s!\n", __func__, r ? "failed" : "passed"); if (out && verbose) fprintf(out, "%s\n", r ? "error" : "ok"); return r; }