1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
/*
* Copyright (C) 2001-2013 Red Hat, Inc.
*
* Michael Fulbright <msf@redhat.com>
* Dustin Kirkland <dustin.dirkland@gmail.com>
* Added support for checkpoint fragment sums;
* Exits media check as soon as bad fragment md5sum'ed
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "md5.h"
#include "libcheckisomd5.h"
#include "utilities.h"
static void clear_appdata(unsigned char *const buffer, const size_t size, const off_t appdata_offset, const off_t offset) {
static const ssize_t buffer_start = 0;
const ssize_t difference = appdata_offset - offset;
if (-APPDATA_SIZE <= difference && difference <= (ssize_t) size) {
const size_t clear_start = (size_t) MAX(buffer_start, difference);
const size_t clear_len = MIN(size, (size_t)(difference + APPDATA_SIZE)) - clear_start;
memset(buffer + clear_start, ' ', clear_len);
}
}
static enum isomd5sum_status checkmd5sum(int isofd, checkCallback cb, void *cbdata) {
struct volume_info *const info = parsepvd(isofd);
if (info == NULL)
return ISOMD5SUM_CHECK_NOT_FOUND;
const off_t total_size = info->isosize - info->skipsectors * SECTOR_SIZE;
const off_t fragment_size = total_size / (info->fragmentcount + 1);
if (cb)
cb(cbdata, 0LL, (long long) total_size);
/* Rewind, compute md5sum. */
lseek(isofd, 0LL, SEEK_SET);
MD5_CTX hashctx;
MD5_Init(&hashctx);
const size_t buffer_size = NUM_SYSTEM_SECTORS * SECTOR_SIZE;
unsigned char *buffer;
buffer = aligned_alloc((size_t) getpagesize(), buffer_size * sizeof(*buffer));
size_t previous_fragment = 0UL;
off_t offset = 0LL;
while (offset < total_size) {
const size_t nbyte = MIN((size_t)(total_size - offset), buffer_size);
ssize_t nread = read(isofd, buffer, nbyte);
if (nread <= 0L)
break;
/**
* Originally was added in 2005 because the kernel was returning the
* size from where it started up to the end of the block it pre-fetched
* from a cd drive.
*/
if (nread > nbyte) {
nread = nbyte;
lseek(isofd, offset + nread, SEEK_SET);
}
/* Make sure appdata which contains the md5sum is cleared. */
clear_appdata(buffer, nread, info->offset + APPDATA_OFFSET, offset);
MD5_Update(&hashctx, buffer, (unsigned int) nread);
if (info->fragmentcount) {
const size_t current_fragment = offset / fragment_size;
const size_t fragmentsize = FRAGMENT_SUM_SIZE / info->fragmentcount;
/* If we're onto the next fragment, calculate the previous sum and check. */
if (current_fragment != previous_fragment) {
if (!validate_fragment(&hashctx, current_fragment, fragmentsize,
info->fragmentsums, NULL)) {
/* Exit immediately if current fragment sum is incorrect */
free(info);
free(buffer);
return ISOMD5SUM_CHECK_FAILED;
}
previous_fragment = current_fragment;
}
}
offset += nread;
if (cb)
if (cb(cbdata, (long long) offset, (long long) total_size)) {
free(info);
free(buffer);
return ISOMD5SUM_CHECK_ABORTED;
}
}
free(buffer);
if (cb)
cb(cbdata, (long long) info->isosize, (long long) total_size);
char hashsum[HASH_SIZE + 1];
md5sum(hashsum, &hashctx);
int failed = strcmp(info->hashsum, hashsum);
free(info);
return failed ? ISOMD5SUM_CHECK_FAILED : ISOMD5SUM_CHECK_PASSED;
}
int mediaCheckFile(const char *file, checkCallback cb, void *cbdata) {
int isofd = open(file, O_RDONLY | O_BINARY);
if (isofd < 0) {
return ISOMD5SUM_FILE_NOT_FOUND;
}
int rc = checkmd5sum(isofd, cb, cbdata);
close(isofd);
return rc;
}
int mediaCheckFD(int isofd, checkCallback cb, void *cbdata) {
return checkmd5sum(isofd, cb, cbdata);
}
int printMD5SUM(const char *file) {
int isofd = open(file, O_RDONLY | O_BINARY);
if (isofd < 0) {
return ISOMD5SUM_FILE_NOT_FOUND;
}
struct volume_info *const info = parsepvd(isofd);
close(isofd);
if (info == NULL) {
return ISOMD5SUM_CHECK_NOT_FOUND;
}
printf("%s: %s\n", file, info->hashsum);
if (strlen(info->fragmentsums) > 0 && info->fragmentcount > 0) {
printf("Fragment sums: %s\n", info->fragmentsums);
printf("Fragment count: %Lu\n", info->fragmentcount);
printf("Supported ISO: %s\n", info->supported ? "yes" : "no");
}
free(info);
return 0;
}
|