-
Notifications
You must be signed in to change notification settings - Fork 13
/
libcheckisomd5.c
157 lines (138 loc) · 5.43 KB
/
libcheckisomd5.c
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: %zu\n", info->fragmentcount);
printf("Supported ISO: %s\n", info->supported ? "yes" : "no");
}
free(info);
return 0;
}