]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
5 | * Common Development and Distribution License (the "License"). | |
6 | * You may not use this file except in compliance with the License. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
13 | * When distributing Covered Code, include this CDDL HEADER in each | |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | * If applicable, add the following below this CDDL HEADER, with the | |
16 | * fields enclosed by brackets "[]" replaced with your own identifying | |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Copyright 2010 Sun Microsystems, Inc. All rights reserved. | |
24 | * Use is subject to license terms. | |
25 | * | |
26 | * Portions Copyright 2012 Martin Matuska <martin@matuska.org> | |
27 | */ | |
28 | ||
29 | /* | |
30 | * Copyright (c) 2013, 2015 by Delphix. All rights reserved. | |
31 | */ | |
32 | ||
33 | #include <ctype.h> | |
34 | #include <libnvpair.h> | |
35 | #include <stdio.h> | |
36 | #include <stdlib.h> | |
37 | #include <strings.h> | |
38 | #include <unistd.h> | |
39 | #include <stddef.h> | |
40 | ||
41 | #include <sys/dmu.h> | |
42 | #include <sys/zfs_ioctl.h> | |
43 | #include <sys/zio.h> | |
44 | #include <zfs_fletcher.h> | |
45 | ||
46 | /* | |
47 | * If dump mode is enabled, the number of bytes to print per line | |
48 | */ | |
49 | #define BYTES_PER_LINE 16 | |
50 | /* | |
51 | * If dump mode is enabled, the number of bytes to group together, separated | |
52 | * by newlines or spaces | |
53 | */ | |
54 | #define DUMP_GROUPING 4 | |
55 | ||
56 | uint64_t total_write_size = 0; | |
57 | uint64_t total_stream_len = 0; | |
58 | FILE *send_stream = 0; | |
59 | boolean_t do_byteswap = B_FALSE; | |
60 | boolean_t do_cksum = B_TRUE; | |
61 | ||
62 | static void | |
63 | usage(void) | |
64 | { | |
65 | (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n"); | |
66 | (void) fprintf(stderr, "\t -v -- verbose\n"); | |
67 | (void) fprintf(stderr, "\t -C -- suppress checksum verification\n"); | |
68 | (void) fprintf(stderr, "\t -d -- dump contents of blocks modified, " | |
69 | "implies verbose\n"); | |
70 | exit(1); | |
71 | } | |
72 | ||
73 | static void * | |
74 | safe_malloc(size_t size) | |
75 | { | |
76 | void *rv = malloc(size); | |
77 | if (rv == NULL) { | |
78 | (void) fprintf(stderr, "ERROR; failed to allocate %zu bytes\n", | |
79 | size); | |
80 | abort(); | |
81 | } | |
82 | return (rv); | |
83 | } | |
84 | ||
85 | /* | |
86 | * ssread - send stream read. | |
87 | * | |
88 | * Read while computing incremental checksum | |
89 | */ | |
90 | static size_t | |
91 | ssread(void *buf, size_t len, zio_cksum_t *cksum) | |
92 | { | |
93 | size_t outlen; | |
94 | ||
95 | if ((outlen = fread(buf, len, 1, send_stream)) == 0) | |
96 | return (0); | |
97 | ||
98 | if (do_cksum) { | |
99 | if (do_byteswap) | |
100 | fletcher_4_incremental_byteswap(buf, len, cksum); | |
101 | else | |
102 | fletcher_4_incremental_native(buf, len, cksum); | |
103 | } | |
104 | total_stream_len += len; | |
105 | return (outlen); | |
106 | } | |
107 | ||
108 | static size_t | |
109 | read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum) | |
110 | { | |
111 | ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), | |
112 | ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t)); | |
113 | size_t r = ssread(drr, sizeof (*drr) - sizeof (zio_cksum_t), cksum); | |
114 | if (r == 0) | |
115 | return (0); | |
116 | zio_cksum_t saved_cksum = *cksum; | |
117 | r = ssread(&drr->drr_u.drr_checksum.drr_checksum, | |
118 | sizeof (zio_cksum_t), cksum); | |
119 | if (r == 0) | |
120 | return (0); | |
121 | if (!ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.drr_checksum.drr_checksum) && | |
122 | !ZIO_CHECKSUM_EQUAL(saved_cksum, | |
123 | drr->drr_u.drr_checksum.drr_checksum)) { | |
124 | fprintf(stderr, "invalid checksum\n"); | |
125 | (void) printf("Incorrect checksum in record header.\n"); | |
126 | (void) printf("Expected checksum = %llx/%llx/%llx/%llx\n", | |
127 | (longlong_t)saved_cksum.zc_word[0], | |
128 | (longlong_t)saved_cksum.zc_word[1], | |
129 | (longlong_t)saved_cksum.zc_word[2], | |
130 | (longlong_t)saved_cksum.zc_word[3]); | |
131 | return (0); | |
132 | } | |
133 | return (sizeof (*drr)); | |
134 | } | |
135 | ||
136 | /* | |
137 | * Print part of a block in ASCII characters | |
138 | */ | |
139 | static void | |
140 | print_ascii_block(char *subbuf, int length) | |
141 | { | |
142 | int i; | |
143 | ||
144 | for (i = 0; i < length; i++) { | |
145 | char char_print = isprint(subbuf[i]) ? subbuf[i] : '.'; | |
146 | if (i != 0 && i % DUMP_GROUPING == 0) { | |
147 | (void) printf(" "); | |
148 | } | |
149 | (void) printf("%c", char_print); | |
150 | } | |
151 | (void) printf("\n"); | |
152 | } | |
153 | ||
154 | /* | |
155 | * print_block - Dump the contents of a modified block to STDOUT | |
156 | * | |
157 | * Assume that buf has capacity evenly divisible by BYTES_PER_LINE | |
158 | */ | |
159 | static void | |
160 | print_block(char *buf, int length) | |
161 | { | |
162 | int i; | |
163 | /* | |
164 | * Start printing ASCII characters at a constant offset, after | |
165 | * the hex prints. Leave 3 characters per byte on a line (2 digit | |
166 | * hex number plus 1 space) plus spaces between characters and | |
167 | * groupings. | |
168 | */ | |
169 | int ascii_start = BYTES_PER_LINE * 3 + | |
170 | BYTES_PER_LINE / DUMP_GROUPING + 2; | |
171 | ||
172 | for (i = 0; i < length; i += BYTES_PER_LINE) { | |
173 | int j; | |
174 | int this_line_length = MIN(BYTES_PER_LINE, length - i); | |
175 | int print_offset = 0; | |
176 | ||
177 | for (j = 0; j < this_line_length; j++) { | |
178 | int buf_offset = i + j; | |
179 | ||
180 | /* | |
181 | * Separate every DUMP_GROUPING bytes by a space. | |
182 | */ | |
183 | if (buf_offset % DUMP_GROUPING == 0) { | |
184 | print_offset += printf(" "); | |
185 | } | |
186 | ||
187 | /* | |
188 | * Print the two-digit hex value for this byte. | |
189 | */ | |
190 | unsigned char hex_print = buf[buf_offset]; | |
191 | print_offset += printf("%02x ", hex_print); | |
192 | } | |
193 | ||
194 | (void) printf("%*s", ascii_start - print_offset, " "); | |
195 | ||
196 | print_ascii_block(buf + i, this_line_length); | |
197 | } | |
198 | } | |
199 | ||
200 | int | |
201 | main(int argc, char *argv[]) | |
202 | { | |
203 | char *buf = safe_malloc(SPA_MAXBLOCKSIZE); | |
204 | uint64_t drr_record_count[DRR_NUMTYPES] = { 0 }; | |
205 | uint64_t total_records = 0; | |
206 | dmu_replay_record_t thedrr; | |
207 | dmu_replay_record_t *drr = &thedrr; | |
208 | struct drr_begin *drrb = &thedrr.drr_u.drr_begin; | |
209 | struct drr_end *drre = &thedrr.drr_u.drr_end; | |
210 | struct drr_object *drro = &thedrr.drr_u.drr_object; | |
211 | struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects; | |
212 | struct drr_write *drrw = &thedrr.drr_u.drr_write; | |
213 | struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref; | |
214 | struct drr_free *drrf = &thedrr.drr_u.drr_free; | |
215 | struct drr_spill *drrs = &thedrr.drr_u.drr_spill; | |
216 | struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded; | |
217 | struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum; | |
218 | char c; | |
219 | boolean_t verbose = B_FALSE; | |
220 | boolean_t very_verbose = B_FALSE; | |
221 | boolean_t first = B_TRUE; | |
222 | /* | |
223 | * dump flag controls whether the contents of any modified data blocks | |
224 | * are printed to the console during processing of the stream. Warning: | |
225 | * for large streams, this can obviously lead to massive prints. | |
226 | */ | |
227 | boolean_t dump = B_FALSE; | |
228 | int err; | |
229 | zio_cksum_t zc = { { 0 } }; | |
230 | zio_cksum_t pcksum = { { 0 } }; | |
231 | ||
232 | while ((c = getopt(argc, argv, ":vCd")) != -1) { | |
233 | switch (c) { | |
234 | case 'C': | |
235 | do_cksum = B_FALSE; | |
236 | break; | |
237 | case 'v': | |
238 | if (verbose) | |
239 | very_verbose = B_TRUE; | |
240 | verbose = B_TRUE; | |
241 | break; | |
242 | case 'd': | |
243 | dump = B_TRUE; | |
244 | verbose = B_TRUE; | |
245 | very_verbose = B_TRUE; | |
246 | break; | |
247 | case ':': | |
248 | (void) fprintf(stderr, | |
249 | "missing argument for '%c' option\n", optopt); | |
250 | usage(); | |
251 | break; | |
252 | case '?': | |
253 | (void) fprintf(stderr, "invalid option '%c'\n", | |
254 | optopt); | |
255 | usage(); | |
256 | break; | |
257 | } | |
258 | } | |
259 | ||
260 | if (isatty(STDIN_FILENO)) { | |
261 | (void) fprintf(stderr, | |
262 | "Error: Backup stream can not be read " | |
263 | "from a terminal.\n" | |
264 | "You must redirect standard input.\n"); | |
265 | exit(1); | |
266 | } | |
267 | ||
268 | fletcher_4_init(); | |
269 | send_stream = stdin; | |
270 | while (read_hdr(drr, &zc)) { | |
271 | ||
272 | /* | |
273 | * If this is the first DMU record being processed, check for | |
274 | * the magic bytes and figure out the endian-ness based on them. | |
275 | */ | |
276 | if (first) { | |
277 | if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { | |
278 | do_byteswap = B_TRUE; | |
279 | if (do_cksum) { | |
280 | ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); | |
281 | /* | |
282 | * recalculate header checksum now | |
283 | * that we know it needs to be | |
284 | * byteswapped. | |
285 | */ | |
286 | fletcher_4_incremental_byteswap(drr, | |
287 | sizeof (dmu_replay_record_t), &zc); | |
288 | } | |
289 | } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) { | |
290 | (void) fprintf(stderr, "Invalid stream " | |
291 | "(bad magic number)\n"); | |
292 | exit(1); | |
293 | } | |
294 | first = B_FALSE; | |
295 | } | |
296 | if (do_byteswap) { | |
297 | drr->drr_type = BSWAP_32(drr->drr_type); | |
298 | drr->drr_payloadlen = | |
299 | BSWAP_32(drr->drr_payloadlen); | |
300 | } | |
301 | ||
302 | /* | |
303 | * At this point, the leading fields of the replay record | |
304 | * (drr_type and drr_payloadlen) have been byte-swapped if | |
305 | * necessary, but the rest of the data structure (the | |
306 | * union of type-specific structures) is still in its | |
307 | * original state. | |
308 | */ | |
309 | if (drr->drr_type >= DRR_NUMTYPES) { | |
310 | (void) printf("INVALID record found: type 0x%x\n", | |
311 | drr->drr_type); | |
312 | (void) printf("Aborting.\n"); | |
313 | exit(1); | |
314 | } | |
315 | ||
316 | drr_record_count[drr->drr_type]++; | |
317 | total_records++; | |
318 | ||
319 | switch (drr->drr_type) { | |
320 | case DRR_BEGIN: | |
321 | if (do_byteswap) { | |
322 | drrb->drr_magic = BSWAP_64(drrb->drr_magic); | |
323 | drrb->drr_versioninfo = | |
324 | BSWAP_64(drrb->drr_versioninfo); | |
325 | drrb->drr_creation_time = | |
326 | BSWAP_64(drrb->drr_creation_time); | |
327 | drrb->drr_type = BSWAP_32(drrb->drr_type); | |
328 | drrb->drr_flags = BSWAP_32(drrb->drr_flags); | |
329 | drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); | |
330 | drrb->drr_fromguid = | |
331 | BSWAP_64(drrb->drr_fromguid); | |
332 | } | |
333 | ||
334 | (void) printf("BEGIN record\n"); | |
335 | (void) printf("\thdrtype = %lld\n", | |
336 | DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo)); | |
337 | (void) printf("\tfeatures = %llx\n", | |
338 | DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo)); | |
339 | (void) printf("\tmagic = %llx\n", | |
340 | (u_longlong_t)drrb->drr_magic); | |
341 | (void) printf("\tcreation_time = %llx\n", | |
342 | (u_longlong_t)drrb->drr_creation_time); | |
343 | (void) printf("\ttype = %u\n", drrb->drr_type); | |
344 | (void) printf("\tflags = 0x%x\n", drrb->drr_flags); | |
345 | (void) printf("\ttoguid = %llx\n", | |
346 | (u_longlong_t)drrb->drr_toguid); | |
347 | (void) printf("\tfromguid = %llx\n", | |
348 | (u_longlong_t)drrb->drr_fromguid); | |
349 | (void) printf("\ttoname = %s\n", drrb->drr_toname); | |
350 | if (verbose) | |
351 | (void) printf("\n"); | |
352 | ||
353 | if (drr->drr_payloadlen != 0) { | |
354 | nvlist_t *nv; | |
355 | int sz = drr->drr_payloadlen; | |
356 | ||
357 | if (sz > SPA_MAXBLOCKSIZE) { | |
358 | free(buf); | |
359 | buf = safe_malloc(sz); | |
360 | } | |
361 | (void) ssread(buf, sz, &zc); | |
362 | if (ferror(send_stream)) | |
363 | perror("fread"); | |
364 | err = nvlist_unpack(buf, sz, &nv, 0); | |
365 | if (err) | |
366 | perror(strerror(err)); | |
367 | nvlist_print(stdout, nv); | |
368 | nvlist_free(nv); | |
369 | } | |
370 | break; | |
371 | ||
372 | case DRR_END: | |
373 | if (do_byteswap) { | |
374 | drre->drr_checksum.zc_word[0] = | |
375 | BSWAP_64(drre->drr_checksum.zc_word[0]); | |
376 | drre->drr_checksum.zc_word[1] = | |
377 | BSWAP_64(drre->drr_checksum.zc_word[1]); | |
378 | drre->drr_checksum.zc_word[2] = | |
379 | BSWAP_64(drre->drr_checksum.zc_word[2]); | |
380 | drre->drr_checksum.zc_word[3] = | |
381 | BSWAP_64(drre->drr_checksum.zc_word[3]); | |
382 | } | |
383 | /* | |
384 | * We compare against the *previous* checksum | |
385 | * value, because the stored checksum is of | |
386 | * everything before the DRR_END record. | |
387 | */ | |
388 | if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum, | |
389 | pcksum)) { | |
390 | (void) printf("Expected checksum differs from " | |
391 | "checksum in stream.\n"); | |
392 | (void) printf("Expected checksum = " | |
393 | "%llx/%llx/%llx/%llx\n", | |
394 | (long long unsigned int)pcksum.zc_word[0], | |
395 | (long long unsigned int)pcksum.zc_word[1], | |
396 | (long long unsigned int)pcksum.zc_word[2], | |
397 | (long long unsigned int)pcksum.zc_word[3]); | |
398 | } | |
399 | (void) printf("END checksum = %llx/%llx/%llx/%llx\n", | |
400 | (long long unsigned int) | |
401 | drre->drr_checksum.zc_word[0], | |
402 | (long long unsigned int) | |
403 | drre->drr_checksum.zc_word[1], | |
404 | (long long unsigned int) | |
405 | drre->drr_checksum.zc_word[2], | |
406 | (long long unsigned int) | |
407 | drre->drr_checksum.zc_word[3]); | |
408 | ||
409 | ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); | |
410 | break; | |
411 | ||
412 | case DRR_OBJECT: | |
413 | if (do_byteswap) { | |
414 | drro->drr_object = BSWAP_64(drro->drr_object); | |
415 | drro->drr_type = BSWAP_32(drro->drr_type); | |
416 | drro->drr_bonustype = | |
417 | BSWAP_32(drro->drr_bonustype); | |
418 | drro->drr_blksz = BSWAP_32(drro->drr_blksz); | |
419 | drro->drr_bonuslen = | |
420 | BSWAP_32(drro->drr_bonuslen); | |
421 | drro->drr_toguid = BSWAP_64(drro->drr_toguid); | |
422 | } | |
423 | if (verbose) { | |
424 | (void) printf("OBJECT object = %llu type = %u " | |
425 | "bonustype = %u blksz = %u bonuslen = %u " | |
426 | "dn_slots = %u\n", | |
427 | (u_longlong_t)drro->drr_object, | |
428 | drro->drr_type, | |
429 | drro->drr_bonustype, | |
430 | drro->drr_blksz, | |
431 | drro->drr_bonuslen, | |
432 | drro->drr_dn_slots); | |
433 | } | |
434 | if (drro->drr_bonuslen > 0) { | |
435 | (void) ssread(buf, | |
436 | P2ROUNDUP(drro->drr_bonuslen, 8), &zc); | |
437 | if (dump) { | |
438 | print_block(buf, | |
439 | P2ROUNDUP(drro->drr_bonuslen, 8)); | |
440 | } | |
441 | } | |
442 | break; | |
443 | ||
444 | case DRR_FREEOBJECTS: | |
445 | if (do_byteswap) { | |
446 | drrfo->drr_firstobj = | |
447 | BSWAP_64(drrfo->drr_firstobj); | |
448 | drrfo->drr_numobjs = | |
449 | BSWAP_64(drrfo->drr_numobjs); | |
450 | drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid); | |
451 | } | |
452 | if (verbose) { | |
453 | (void) printf("FREEOBJECTS firstobj = %llu " | |
454 | "numobjs = %llu\n", | |
455 | (u_longlong_t)drrfo->drr_firstobj, | |
456 | (u_longlong_t)drrfo->drr_numobjs); | |
457 | } | |
458 | break; | |
459 | ||
460 | case DRR_WRITE: | |
461 | if (do_byteswap) { | |
462 | drrw->drr_object = BSWAP_64(drrw->drr_object); | |
463 | drrw->drr_type = BSWAP_32(drrw->drr_type); | |
464 | drrw->drr_offset = BSWAP_64(drrw->drr_offset); | |
465 | drrw->drr_logical_size = | |
466 | BSWAP_64(drrw->drr_logical_size); | |
467 | drrw->drr_toguid = BSWAP_64(drrw->drr_toguid); | |
468 | drrw->drr_key.ddk_prop = | |
469 | BSWAP_64(drrw->drr_key.ddk_prop); | |
470 | drrw->drr_compressed_size = | |
471 | BSWAP_64(drrw->drr_compressed_size); | |
472 | } | |
473 | ||
474 | uint64_t payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw); | |
475 | ||
476 | /* | |
477 | * If this is verbose and/or dump output, | |
478 | * print info on the modified block | |
479 | */ | |
480 | if (verbose) { | |
481 | (void) printf("WRITE object = %llu type = %u " | |
482 | "checksum type = %u compression type = %u\n" | |
483 | " offset = %llu logical_size = %llu " | |
484 | "compressed_size = %llu " | |
485 | "payload_size = %llu " | |
486 | "props = %llx\n", | |
487 | (u_longlong_t)drrw->drr_object, | |
488 | drrw->drr_type, | |
489 | drrw->drr_checksumtype, | |
490 | drrw->drr_compressiontype, | |
491 | (u_longlong_t)drrw->drr_offset, | |
492 | (u_longlong_t)drrw->drr_logical_size, | |
493 | (u_longlong_t)drrw->drr_compressed_size, | |
494 | (u_longlong_t)payload_size, | |
495 | (u_longlong_t)drrw->drr_key.ddk_prop); | |
496 | } | |
497 | ||
498 | /* | |
499 | * Read the contents of the block in from STDIN to buf | |
500 | */ | |
501 | (void) ssread(buf, payload_size, &zc); | |
502 | /* | |
503 | * If in dump mode | |
504 | */ | |
505 | if (dump) { | |
506 | print_block(buf, payload_size); | |
507 | } | |
508 | total_write_size += payload_size; | |
509 | break; | |
510 | ||
511 | case DRR_WRITE_BYREF: | |
512 | if (do_byteswap) { | |
513 | drrwbr->drr_object = | |
514 | BSWAP_64(drrwbr->drr_object); | |
515 | drrwbr->drr_offset = | |
516 | BSWAP_64(drrwbr->drr_offset); | |
517 | drrwbr->drr_length = | |
518 | BSWAP_64(drrwbr->drr_length); | |
519 | drrwbr->drr_toguid = | |
520 | BSWAP_64(drrwbr->drr_toguid); | |
521 | drrwbr->drr_refguid = | |
522 | BSWAP_64(drrwbr->drr_refguid); | |
523 | drrwbr->drr_refobject = | |
524 | BSWAP_64(drrwbr->drr_refobject); | |
525 | drrwbr->drr_refoffset = | |
526 | BSWAP_64(drrwbr->drr_refoffset); | |
527 | drrwbr->drr_key.ddk_prop = | |
528 | BSWAP_64(drrwbr->drr_key.ddk_prop); | |
529 | } | |
530 | if (verbose) { | |
531 | (void) printf("WRITE_BYREF object = %llu " | |
532 | "checksum type = %u props = %llx\n" | |
533 | " offset = %llu length = %llu\n" | |
534 | "toguid = %llx refguid = %llx\n" | |
535 | " refobject = %llu refoffset = %llu\n", | |
536 | (u_longlong_t)drrwbr->drr_object, | |
537 | drrwbr->drr_checksumtype, | |
538 | (u_longlong_t)drrwbr->drr_key.ddk_prop, | |
539 | (u_longlong_t)drrwbr->drr_offset, | |
540 | (u_longlong_t)drrwbr->drr_length, | |
541 | (u_longlong_t)drrwbr->drr_toguid, | |
542 | (u_longlong_t)drrwbr->drr_refguid, | |
543 | (u_longlong_t)drrwbr->drr_refobject, | |
544 | (u_longlong_t)drrwbr->drr_refoffset); | |
545 | } | |
546 | break; | |
547 | ||
548 | case DRR_FREE: | |
549 | if (do_byteswap) { | |
550 | drrf->drr_object = BSWAP_64(drrf->drr_object); | |
551 | drrf->drr_offset = BSWAP_64(drrf->drr_offset); | |
552 | drrf->drr_length = BSWAP_64(drrf->drr_length); | |
553 | } | |
554 | if (verbose) { | |
555 | (void) printf("FREE object = %llu " | |
556 | "offset = %llu length = %lld\n", | |
557 | (u_longlong_t)drrf->drr_object, | |
558 | (u_longlong_t)drrf->drr_offset, | |
559 | (longlong_t)drrf->drr_length); | |
560 | } | |
561 | break; | |
562 | case DRR_SPILL: | |
563 | if (do_byteswap) { | |
564 | drrs->drr_object = BSWAP_64(drrs->drr_object); | |
565 | drrs->drr_length = BSWAP_64(drrs->drr_length); | |
566 | } | |
567 | if (verbose) { | |
568 | (void) printf("SPILL block for object = %llu " | |
569 | "length = %llu\n", | |
570 | (long long unsigned int)drrs->drr_object, | |
571 | (long long unsigned int)drrs->drr_length); | |
572 | } | |
573 | (void) ssread(buf, drrs->drr_length, &zc); | |
574 | if (dump) { | |
575 | print_block(buf, drrs->drr_length); | |
576 | } | |
577 | break; | |
578 | case DRR_WRITE_EMBEDDED: | |
579 | if (do_byteswap) { | |
580 | drrwe->drr_object = | |
581 | BSWAP_64(drrwe->drr_object); | |
582 | drrwe->drr_offset = | |
583 | BSWAP_64(drrwe->drr_offset); | |
584 | drrwe->drr_length = | |
585 | BSWAP_64(drrwe->drr_length); | |
586 | drrwe->drr_toguid = | |
587 | BSWAP_64(drrwe->drr_toguid); | |
588 | drrwe->drr_lsize = | |
589 | BSWAP_32(drrwe->drr_lsize); | |
590 | drrwe->drr_psize = | |
591 | BSWAP_32(drrwe->drr_psize); | |
592 | } | |
593 | if (verbose) { | |
594 | (void) printf("WRITE_EMBEDDED object = %llu " | |
595 | "offset = %llu length = %llu\n" | |
596 | " toguid = %llx comp = %u etype = %u " | |
597 | "lsize = %u psize = %u\n", | |
598 | (u_longlong_t)drrwe->drr_object, | |
599 | (u_longlong_t)drrwe->drr_offset, | |
600 | (u_longlong_t)drrwe->drr_length, | |
601 | (u_longlong_t)drrwe->drr_toguid, | |
602 | drrwe->drr_compression, | |
603 | drrwe->drr_etype, | |
604 | drrwe->drr_lsize, | |
605 | drrwe->drr_psize); | |
606 | } | |
607 | (void) ssread(buf, | |
608 | P2ROUNDUP(drrwe->drr_psize, 8), &zc); | |
609 | break; | |
610 | case DRR_NUMTYPES: | |
611 | /* should never be reached */ | |
612 | exit(1); | |
613 | } | |
614 | if (drr->drr_type != DRR_BEGIN && very_verbose) { | |
615 | (void) printf(" checksum = %llx/%llx/%llx/%llx\n", | |
616 | (longlong_t)drrc->drr_checksum.zc_word[0], | |
617 | (longlong_t)drrc->drr_checksum.zc_word[1], | |
618 | (longlong_t)drrc->drr_checksum.zc_word[2], | |
619 | (longlong_t)drrc->drr_checksum.zc_word[3]); | |
620 | } | |
621 | pcksum = zc; | |
622 | } | |
623 | free(buf); | |
624 | fletcher_4_fini(); | |
625 | ||
626 | /* Print final summary */ | |
627 | ||
628 | (void) printf("SUMMARY:\n"); | |
629 | (void) printf("\tTotal DRR_BEGIN records = %lld\n", | |
630 | (u_longlong_t)drr_record_count[DRR_BEGIN]); | |
631 | (void) printf("\tTotal DRR_END records = %lld\n", | |
632 | (u_longlong_t)drr_record_count[DRR_END]); | |
633 | (void) printf("\tTotal DRR_OBJECT records = %lld\n", | |
634 | (u_longlong_t)drr_record_count[DRR_OBJECT]); | |
635 | (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n", | |
636 | (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]); | |
637 | (void) printf("\tTotal DRR_WRITE records = %lld\n", | |
638 | (u_longlong_t)drr_record_count[DRR_WRITE]); | |
639 | (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n", | |
640 | (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]); | |
641 | (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n", | |
642 | (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]); | |
643 | (void) printf("\tTotal DRR_FREE records = %lld\n", | |
644 | (u_longlong_t)drr_record_count[DRR_FREE]); | |
645 | (void) printf("\tTotal DRR_SPILL records = %lld\n", | |
646 | (u_longlong_t)drr_record_count[DRR_SPILL]); | |
647 | (void) printf("\tTotal records = %lld\n", | |
648 | (u_longlong_t)total_records); | |
649 | (void) printf("\tTotal write size = %lld (0x%llx)\n", | |
650 | (u_longlong_t)total_write_size, (u_longlong_t)total_write_size); | |
651 | (void) printf("\tTotal stream length = %lld (0x%llx)\n", | |
652 | (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len); | |
653 | return (0); | |
654 | } |