1 /* $Id: verify.c,v 1.3 2005/05/13 18:52:06 harbourn Exp $
2 * dcfldd - The Enhanced Forensic DD
3 * By Nicholas Harbour
4 */
5
6 /* Copyright 85, 90, 91, 1995-2001, 2005 Free Software Foundation, Inc.
7 Copyright 2015 Joao Eriberto Mota Filho <eriberto@eriberto.pro.br>
8 Copyright 2019 Bernhard Übelacker <bernhardu@mailbox.org>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
23
24 /* GNU dd originally written by Paul Rubin, David MacKenzie, and Stuart Kemp. */
25
26 #include "dcfldd.h"
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <string.h>
30 #include "config.h"
31 #include "hash.h"
32 #include "getpagesize.h"
33 #include "safe-read.h"
34 #include "sizeprobe.h"
35 #include "pattern.h"
36 #include "util.h"
37 #include "log.h"
38
39 static int verify_update(hashlist_t *, void *, void *, size_t, size_t);
40 static void verify_remainder(hashlist_t *);
41
42 /* The name of the verify file, or NULL if none.
43 * Verify file is used as a secondary input file and the input
44 * file is compared against it via the use of their hashes. */
45 char *verify_file = NULL;
46 int verify_fd;
47 FILE *verify_log;
48
49 /* Skip this many records of `input_blocksize' bytes before reading */
50 uintmax_t vskip_records = 0;
51
verify_update(hashlist_t * hashl,void * ibuf,void * vbuf,size_t ilen,size_t vlen)52 static int verify_update(hashlist_t *hashl,
53 void *ibuf, void *vbuf,
54 size_t ilen, size_t vlen)
55 {
56 size_t left_in_window = hash_windowlen - (bytes_in_window);
57 int cmp = 0;
58
59 if (bytes_in_total == 0) {
60 hashl_init(hashl, TOTAL_CTX);
61 hashl_init(hashl, VTOTAL_CTX);
62 }
63
64 if (hash_windowlen == 0) {
65 hash_update_buf(hashl, WINDOW_CTX, TOTAL_CTX, ibuf, ilen);
66 hash_update_buf(hashl, VWINDOW_CTX, VTOTAL_CTX, vbuf, vlen);
67 } else {
68 if (bytes_in_window == 0) {
69 hashl_init(hashl, WINDOW_CTX);
70 hashl_init(hashl, VWINDOW_CTX);
71 }
72
73 if (ilen >= left_in_window || vlen >= left_in_window) {
74 char *ihash, *vhash;
75
76 hash_update_buf(hashl, WINDOW_CTX, TOTAL_CTX,
77 ibuf, min(ilen, left_in_window));
78 hash_update_buf(hashl, VWINDOW_CTX, VTOTAL_CTX,
79 vbuf, min(vlen, left_in_window));
80
81 /* if verify ever wants to do more than one hash, change this */
82 hashl_final(hashl, WINDOW_CTX);
83 ihash = strdup(hashl->hash->hashstr_buf);
84 hashl_final(hashl, VWINDOW_CTX);
85 vhash = hashl->hash->hashstr_buf;
86
87 cmp = memcmp(ihash, vhash, hashl->hash->hashstr_buf_size);
88 free(ihash);
89
90 if (cmp != 0)
91 {
92 log_verifywindow(hashl->hash, window_beginning,
93 (window_beginning + hash_windowlen), cmp);
94 return 1;
95 }
96
97 window_beginning += hash_windowlen;
98
99 bytes_in_window = 0;
100
101 verify_update(hashl, ibuf + left_in_window, vbuf + left_in_window,
102 ilen - left_in_window, vlen - left_in_window);
103 } else {
104 hash_update_buf(hashl, WINDOW_CTX, TOTAL_CTX, ibuf, ilen);
105 hash_update_buf(hashl, VWINDOW_CTX, VTOTAL_CTX, vbuf, vlen);
106 }
107 }
108
109 return 0;
110 }
111
verify_remainder(hashlist_t * hashl)112 static void verify_remainder(hashlist_t *hashl)
113 {
114 int cmp = 0;
115
116 if (hash_windowlen > 0 && bytes_in_window > 0) {
117 char *ihash, *vhash;
118
119 hashl_final(hashl, WINDOW_CTX);
120 ihash = strdup(hashl->hash->hashstr_buf);
121 hashl_final(hashl, VWINDOW_CTX);
122 vhash = hashl->hash->hashstr_buf;
123
124 cmp = memcmp(ihash, vhash, hashl->hash->hashstr_buf_size);
125 free(ihash);
126
127 if (cmp != 0)
128 log_verifywindow(hashl->hash, window_beginning,
129 (window_beginning + hash_windowlen), cmp);
130 }
131 }
132
133 /* The main loop when using the verify option. */
dd_verify(void)134 int dd_verify(void)
135 {
136 unsigned char *ibuf; /* Input buffer. */
137 unsigned char *vbuf; /* Verify buffer. */
138 unsigned char *real_ibuf;
139 unsigned char *real_vbuf;
140 ssize_t i_nread; /* Bytes read in the current input block. */
141 ssize_t v_nread; /* Bytes read in the current verify block. */
142 int exit_status = 0;
143 int input_from_stream = !!input_file;
144 int input_from_pattern = !input_from_stream;
145 size_t page_size = getpagesize();
146 size_t n_bytes_read;
147 char *i_hashstr_buf;
148 char *v_hashstr_buf;
149 size_t left_in_window;
150 int mismatch = 0;
151 int cmp = 0;
152
153 real_ibuf = (unsigned char *) malloc(input_blocksize
154 + 2 * SWAB_ALIGN_OFFSET
155 + 2 * page_size - 1);
156 ibuf = real_ibuf;
157 ibuf += SWAB_ALIGN_OFFSET; /* allow space for swab */
158
159 ibuf = PTR_ALIGN(ibuf, page_size);
160
161 real_vbuf = (unsigned char *) malloc(input_blocksize
162 + 2 * SWAB_ALIGN_OFFSET
163 + 2 * page_size - 1);
164 vbuf = real_vbuf;
165 vbuf += SWAB_ALIGN_OFFSET; /* allow space for swab */
166
167 vbuf = PTR_ALIGN(vbuf, page_size);
168
169 i_hashstr_buf = malloc(hashstr_buf_size);
170 v_hashstr_buf = malloc(hashstr_buf_size);
171
172 if (!input_from_pattern)
173 if (skip_records != 0)
174 skip(STDIN_FILENO, input_file, skip_records, input_blocksize, ibuf);
175
176 if (vskip_records != 0)
177 skip(verify_fd, verify_file, vskip_records, input_blocksize, vbuf);
178
179 if (max_records == 0)
180 quit(exit_status);
181
182 if (input_from_pattern) {
183 replicate_pattern(pattern, ibuf, input_blocksize);
184 i_nread = input_blocksize;
185 }
186
187 while (1)
188 {
189 /* Display an update message */
190 if (do_status && w_full % update_thresh == 0 && w_full != 0)
191 {
192 off_t total_bytes = w_full * input_blocksize;
193 off_t total_mb = total_bytes / 1048576;
194
195 if (probe == PROBE_NONE || probed_size == 0)
196 fprintf(stderr, "\r%llu blocks (%lluMb) written.",
197 /* [FIX] verify.c:195:25: warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument {3,4} has type ‘uintmax_t’ [-Wformat=] */
198 (long long unsigned int) w_full, (long long unsigned int) total_mb);
199 else {
200 time_t curr_time = time(NULL);
201 int seconds = (int)difftime(curr_time, start_time);
202 off_t probed_mb = probed_size / 1048576;
203 float fprcnt = total_bytes / (float)probed_size;
204 float fprcnt_remaining = 1.0 - fprcnt;
205 int prcnt = (int)(fprcnt * 100);
206 int seconds_remaining = (int)(seconds *
207 (fprcnt_remaining / fprcnt));
208 char secstr[100];
209
210 time_left(secstr, sizeof secstr, seconds_remaining);
211 fprintf(stderr,
212 "\r[%d%% of %lluMb] %llu blocks (%lluMb) written. %s",
213 /* [FIX] verify.c:210:25: warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument {4,5,6} has type ‘off_t’ [-Wformat=] */
214 prcnt, (long long unsigned int) probed_mb, (long long unsigned int) w_full, (long long unsigned int) total_mb, secstr);
215 }
216 }
217
218 if (r_partial + r_full >= max_records)
219 break;
220
221 v_nread = safe_read(verify_fd, vbuf, input_blocksize);
222
223 if (v_nread < 0)
224 syscall_error(input_file);
225
226 /* Zero the buffer before reading, so that if we get a read error,
227 whatever data we are able to read is followed by zeros.
228 This minimizes data loss. */
229 if (input_from_pattern) {
230 replicate_pattern(pattern, ibuf, v_nread);
231 i_nread = v_nread;
232 } else
233 i_nread = safe_read(STDIN_FILENO, ibuf, input_blocksize);
234
235 if (i_nread < 0 && !input_from_pattern)
236 syscall_error(input_file);
237
238 if (i_nread == 0 && v_nread == 0)
239 break;
240
241 left_in_window = hash_windowlen - bytes_in_window;
242 mismatch = verify_update(ihashlist, ibuf, vbuf, i_nread, v_nread);
243
244 if (i_nread != v_nread || (mismatch && i_nread < left_in_window)) {
245 log_verifywindow(ihashlist->hash, window_beginning,
246 (window_beginning + bytes_in_window), 1);
247 mismatch = 1;
248 }
249
250 if (mismatch)
251 break;
252 }
253
254 free(real_ibuf);
255 free(real_vbuf);
256
257 /* verifying a remainder and total wouldnt make sense if we
258 * they won't match due to different amounts read.
259 */
260 if (!mismatch) {
261 char *ihash, *vhash;
262
263 verify_remainder(ihashlist);
264
265 hashl_final(ihashlist, TOTAL_CTX);
266 ihash = strdup(ihashlist->hash->hashstr_buf);
267 hashl_final(ihashlist, VTOTAL_CTX);
268 vhash = ihashlist->hash->hashstr_buf;
269
270 cmp = memcmp(ihash, vhash, ihashlist->hash->hashstr_buf_size);
271 free(ihash);
272
273 if (cmp != 0)
274 log_verifywindow(ihashlist->hash, window_beginning,
275 (window_beginning + bytes_in_window), cmp);
276
277 log_verifytotal(ihashlist->hash, cmp);
278 } else
279 log_verifytotal(ihashlist->hash, 1);
280
281 return exit_status;
282 }
283