Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <stdio.h>
36 : : #include <errno.h>
37 : : #include <fcntl.h>
38 : : #include <stdlib.h>
39 : : #include <unistd.h>
40 : : #include <inttypes.h>
41 : :
42 : : #include "libvhd.h"
43 : : #include "vhd-util.h"
44 : :
45 : : #define nsize 21
46 : : static char nbuf[nsize];
47 : :
48 : : static inline char *
49 : : __xconv(uint64_t num)
50 : : {
51 : : snprintf(nbuf, nsize, "%#" PRIx64 , num);
52 : : return nbuf;
53 : : }
54 : :
55 : : static inline char *
56 : : __dconv(uint64_t num)
57 : : {
58 : : snprintf(nbuf, nsize, "%" PRIu64, num);
59 : : return nbuf;
60 : : }
61 : :
62 : : #define conv(hex, num) \
63 : : (hex ? __xconv((uint64_t)num) : __dconv((uint64_t)num))
64 : :
65 : : static void
66 : 0 : vhd_print_header(vhd_context_t *vhd, vhd_header_t *h, int hex)
67 : : {
68 : : int err;
69 : : uint32_t cksm;
70 : : char uuid[37], time_str[26], cookie[9], *name;
71 : :
72 : : printf("VHD Header Summary:\n-------------------\n");
73 : :
74 : 0 : snprintf(cookie, 9, "%s", h->cookie);
75 : : printf("Cookie : %s\n", cookie);
76 : :
77 [ # # ]: 0 : printf("Data offset (unusd) : %s\n", conv(hex, h->data_offset));
78 [ # # ]: 0 : printf("Table offset : %s\n", conv(hex, h->table_offset));
79 : 0 : printf("Header version : 0x%08x\n", h->hdr_ver);
80 [ # # ]: 0 : printf("Max BAT size : %s\n", conv(hex, h->max_bat_size));
81 [ # # ]: 0 : printf("Block size : %s ", conv(hex, h->block_size));
82 [ # # ]: 0 : printf("(%s MB)\n", conv(hex, h->block_size >> 20));
83 : :
84 : 0 : err = vhd_header_decode_parent(vhd, h, &name);
85 [ # # ]: 0 : printf("Parent name : %s\n",
86 : : (err ? "failed to read name" : name));
87 : 0 : free(name);
88 : :
89 : 0 : uuid_unparse(h->prt_uuid, uuid);
90 : : printf("Parent UUID : %s\n", uuid);
91 : :
92 : 0 : vhd_time_to_string(h->prt_ts, time_str);
93 : : printf("Parent timestamp : %s\n", time_str);
94 : :
95 : 0 : cksm = vhd_checksum_header(h);
96 [ # # ]: 0 : printf("Checksum : 0x%x|0x%x (%s)\n", h->checksum, cksm,
97 : 0 : h->checksum == cksm ? "Good!" : "Bad!");
98 : : printf("\n");
99 : 0 : }
100 : :
101 : : /* String table for hd.type */
102 : : char *hd_type_str[7] = {
103 : : "None", /* 0 */
104 : : "Reserved (deprecated)", /* 1 */
105 : : "Fixed hard disk", /* 2 */
106 : : "Dynamic hard disk", /* 3 */
107 : : "Differencing hard disk", /* 4 */
108 : : "Reserved (deprecated)", /* 5 */
109 : : "Reserved (deprecated)" /* 6 */
110 : : };
111 : :
112 : : static void
113 : 0 : vhd_print_footer(vhd_footer_t *f, int hex)
114 : : {
115 : : uint64_t c, h, s;
116 : : uint32_t ff_maj, ff_min, cr_maj, cr_min, cksm;
117 : : char time_str[26], creator[5], uuid[37], cookie[9];
118 : :
119 : : printf("VHD Footer Summary:\n-------------------\n");
120 : :
121 : 0 : snprintf(cookie, 9, "%s", f->cookie);
122 : : printf("Cookie : %s\n", cookie);
123 : :
124 [ # # ][ # # ]: 0 : printf("Features : (0x%08x) %s%s\n", f->features,
125 : 0 : (f->features & HD_TEMPORARY) ? "<TEMP>" : "",
126 : 0 : (f->features & HD_RESERVED) ? "<RESV>" : "");
127 : :
128 : 0 : ff_maj = f->ff_version >> 16;
129 : 0 : ff_min = f->ff_version & 0xffff;
130 : : printf("File format version : Major: %d, Minor: %d\n",
131 : : ff_maj, ff_min);
132 : :
133 [ # # ]: 0 : printf("Data offset : %s\n", conv(hex, f->data_offset));
134 : :
135 : 0 : vhd_time_to_string(f->timestamp, time_str);
136 : : printf("Timestamp : %s\n", time_str);
137 : :
138 : 0 : memcpy(creator, f->crtr_app, 4);
139 : 0 : creator[4] = '\0';
140 : : printf("Creator Application : '%s'\n", creator);
141 : :
142 : 0 : cr_maj = f->crtr_ver >> 16;
143 : 0 : cr_min = f->crtr_ver & 0xffff;
144 : : printf("Creator version : Major: %d, Minor: %d\n",
145 : : cr_maj, cr_min);
146 : :
147 [ # # ]: 0 : printf("Creator OS : %s\n",
148 : 0 : ((f->crtr_os == HD_CR_OS_WINDOWS) ? "Windows" :
149 [ # # ]: 0 : ((f->crtr_os == HD_CR_OS_MACINTOSH) ? "Macintosh" :
150 : : "Unknown!")));
151 : :
152 [ # # ]: 0 : printf("Original disk size : %s MB ", conv(hex, f->orig_size >> 20));
153 [ # # ]: 0 : printf("(%s Bytes)\n", conv(hex, f->orig_size));
154 : :
155 [ # # ]: 0 : printf("Current disk size : %s MB ", conv(hex, f->curr_size >> 20));
156 [ # # ]: 0 : printf("(%s Bytes)\n", conv(hex, f->curr_size));
157 : :
158 : 0 : c = f->geometry >> 16;
159 : 0 : h = (f->geometry & 0x0000FF00) >> 8;
160 : 0 : s = f->geometry & 0x000000FF;
161 [ # # ]: 0 : printf("Geometry : Cyl: %s, ", conv(hex, c));
162 [ # # ]: 0 : printf("Hds: %s, ", conv(hex, h));
163 [ # # ]: 0 : printf("Sctrs: %s\n", conv(hex, s));
164 [ # # ]: 0 : printf(" : = %s MB ", conv(hex, (c * h * s) >> 11));
165 [ # # ]: 0 : printf("(%s Bytes)\n", conv(hex, c * h * s << 9));
166 : :
167 [ # # ]: 0 : printf("Disk type : %s\n",
168 : 0 : f->type <= HD_TYPE_MAX ?
169 : : hd_type_str[f->type] : "Unknown type!\n");
170 : :
171 : 0 : cksm = vhd_checksum_footer(f);
172 [ # # ]: 0 : printf("Checksum : 0x%x|0x%x (%s)\n", f->checksum, cksm,
173 : 0 : f->checksum == cksm ? "Good!" : "Bad!");
174 : :
175 : 0 : uuid_unparse(f->uuid, uuid);
176 : : printf("UUID : %s\n", uuid);
177 : :
178 [ # # ]: 0 : printf("Saved state : %s\n", f->saved == 0 ? "No" : "Yes");
179 : 0 : printf("Hidden : %d\n", f->hidden);
180 : : printf("\n");
181 : 0 : }
182 : :
183 : : static inline char *
184 : 0 : code_name(uint32_t code)
185 : : {
186 [ # # # # : 0 : switch(code) {
# # # # ]
187 : : case PLAT_CODE_NONE:
188 : : return "PLAT_CODE_NONE";
189 : : case PLAT_CODE_WI2R:
190 : 0 : return "PLAT_CODE_WI2R";
191 : : case PLAT_CODE_WI2K:
192 : 0 : return "PLAT_CODE_WI2K";
193 : : case PLAT_CODE_W2RU:
194 : 0 : return "PLAT_CODE_W2RU";
195 : : case PLAT_CODE_W2KU:
196 : 0 : return "PLAT_CODE_W2KU";
197 : : case PLAT_CODE_MAC:
198 : 0 : return "PLAT_CODE_MAC";
199 : : case PLAT_CODE_MACX:
200 : 0 : return "PLAT_CODE_MACX";
201 : : default:
202 : 0 : return "UNKOWN";
203 : : }
204 : : }
205 : :
206 : : static void
207 : 0 : vhd_print_parent(vhd_context_t *vhd, vhd_parent_locator_t *loc)
208 : : {
209 : : int err;
210 : : char *buf;
211 : :
212 : 0 : err = vhd_parent_locator_read(vhd, loc, &buf);
213 [ # # ]: 0 : if (err) {
214 : : printf("failed to read parent name\n");
215 : 0 : return;
216 : : }
217 : :
218 : 0 : printf(" decoded name : %s\n", buf);
219 : 0 : free(buf);
220 : : }
221 : :
222 : : static void
223 : 0 : vhd_print_parent_locators(vhd_context_t *vhd, int hex)
224 : : {
225 : : int i, n;
226 : : vhd_parent_locator_t *loc;
227 : :
228 : : printf("VHD Parent Locators:\n--------------------\n");
229 : :
230 : 0 : n = sizeof(vhd->header.loc) / sizeof(struct prt_loc);
231 [ # # ]: 0 : for (i = 0; i < n; i++) {
232 : 0 : loc = &vhd->header.loc[i];
233 : :
234 [ # # ]: 0 : if (loc->code == PLAT_CODE_NONE)
235 : 0 : continue;
236 : :
237 : : printf("locator: : %d\n", i);
238 : 0 : printf(" code : %s\n",
239 : : code_name(loc->code));
240 [ # # ]: 0 : printf(" data_space : %s\n",
241 : 0 : conv(hex, loc->data_space));
242 [ # # ]: 0 : printf(" data_length : %s\n",
243 : 0 : conv(hex, loc->data_len));
244 [ # # ]: 0 : printf(" data_offset : %s\n",
245 : 0 : conv(hex, loc->data_offset));
246 : 0 : vhd_print_parent(vhd, loc);
247 : : printf("\n");
248 : : }
249 : 0 : }
250 : :
251 : : static void
252 : 0 : vhd_print_keyhash(vhd_context_t *vhd)
253 : : {
254 : : int ret;
255 : : struct vhd_keyhash keyhash;
256 : :
257 : 0 : ret = vhd_get_keyhash(vhd, &keyhash);
258 [ # # ]: 0 : if (ret)
259 : : printf("error reading keyhash: %d\n", ret);
260 [ # # ]: 0 : else if (keyhash.cookie == 1) {
261 : : int i;
262 : :
263 : : printf("Batmap keyhash nonce: ");
264 [ # # ]: 0 : for (i = 0; i < sizeof(keyhash.nonce); i++)
265 : 0 : printf("%02x", keyhash.nonce[i]);
266 : :
267 : : printf("\nBatmap keyhash hash : ");
268 [ # # ]: 0 : for (i = 0; i < sizeof(keyhash.hash); i++)
269 : 0 : printf("%02x", keyhash.hash[i]);
270 : :
271 : : printf("\n");
272 : : }
273 : 0 : }
274 : :
275 : : static void
276 : 0 : vhd_print_batmap_header(vhd_context_t *vhd, vhd_batmap_t *batmap, int hex)
277 : : {
278 : : uint32_t cksm;
279 : :
280 : : printf("VHD Batmap Summary:\n-------------------\n");
281 [ # # ]: 0 : printf("Batmap offset : %s\n",
282 : 0 : conv(hex, batmap->header.batmap_offset));
283 [ # # ]: 0 : printf("Batmap size (secs) : %s\n",
284 : 0 : conv(hex, batmap->header.batmap_size));
285 : 0 : printf("Batmap version : 0x%08x\n",
286 : : batmap->header.batmap_version);
287 : 0 : vhd_print_keyhash(vhd);
288 : :
289 : 0 : cksm = vhd_checksum_batmap(vhd, batmap);
290 [ # # ]: 0 : printf("Checksum : 0x%x|0x%x (%s)\n",
291 : : batmap->header.checksum, cksm,
292 : 0 : (batmap->header.checksum == cksm ? "Good!" : "Bad!"));
293 : : printf("\n");
294 : 0 : }
295 : :
296 : : static inline int
297 : 0 : check_block_range(vhd_context_t *vhd, uint64_t block, int hex)
298 : : {
299 [ # # ]: 0 : if (block > vhd->header.max_bat_size) {
300 [ # # ]: 0 : fprintf(stderr, "block %s past end of file\n",
301 : : conv(hex, block));
302 : 0 : return -ERANGE;
303 : : }
304 : :
305 : : return 0;
306 : : }
307 : :
308 : : static int
309 : 0 : vhd_print_headers(vhd_context_t *vhd, int hex)
310 : : {
311 : : int err;
312 : :
313 : 0 : vhd_print_footer(&vhd->footer, hex);
314 : :
315 [ # # ]: 0 : if (vhd_type_dynamic(vhd)) {
316 : 0 : vhd_print_header(vhd, &vhd->header, hex);
317 : :
318 [ # # ]: 0 : if (vhd->footer.type == HD_TYPE_DIFF)
319 : 0 : vhd_print_parent_locators(vhd, hex);
320 : :
321 [ # # ]: 0 : if (vhd_has_batmap(vhd)) {
322 : 0 : err = vhd_get_batmap(vhd);
323 [ # # ]: 0 : if (err) {
324 : : printf("failed to get batmap header\n");
325 : 0 : return err;
326 : : }
327 : :
328 : 0 : vhd_print_batmap_header(vhd, &vhd->batmap, hex);
329 : : }
330 : : }
331 : :
332 : : return 0;
333 : : }
334 : :
335 : : static int
336 : 0 : vhd_dump_headers(const char *name, int hex)
337 : : {
338 : : vhd_context_t vhd;
339 : :
340 : 0 : libvhd_set_log_level(1);
341 : : memset(&vhd, 0, sizeof(vhd));
342 : :
343 : : printf("\n%s appears invalid; dumping headers\n\n", name);
344 : :
345 : 0 : vhd.fd = open_optional_odirect(name, O_DIRECT | O_LARGEFILE | O_RDONLY);
346 [ # # ]: 0 : if (vhd.fd == -1)
347 : 0 : return -errno;
348 : :
349 : 0 : vhd.file = strdup(name);
350 : :
351 : 0 : vhd_read_footer(&vhd, &vhd.footer, false);
352 : 0 : vhd_read_header(&vhd, &vhd.header);
353 : :
354 : 0 : vhd_print_footer(&vhd.footer, hex);
355 : 0 : vhd_print_header(&vhd, &vhd.header, hex);
356 : :
357 : 0 : close(vhd.fd);
358 : 0 : free(vhd.file);
359 : :
360 : 0 : return 0;
361 : : }
362 : :
363 : : static int
364 : 0 : vhd_print_logical_to_physical(vhd_context_t *vhd,
365 : : uint64_t sector, int count, int hex)
366 : : {
367 : : int i;
368 : : uint32_t blk, lsec;
369 : : uint64_t cur, offset;
370 : :
371 [ # # ]: 0 : if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
372 [ # # ]: 0 : fprintf(stderr, "sector %s past end of file\n",
373 : 0 : conv(hex, sector + count));
374 : 0 : return -ERANGE;
375 : : }
376 : :
377 [ # # ]: 0 : for (i = 0; i < count; i++) {
378 : 0 : cur = sector + i;
379 : 0 : blk = cur / vhd->spb;
380 : 0 : lsec = cur % vhd->spb;
381 : 0 : offset = vhd->bat.bat[blk];
382 : :
383 [ # # ]: 0 : if (offset != DD_BLK_UNUSED) {
384 : 0 : offset += lsec + 1;
385 : 0 : offset = vhd_sectors_to_bytes(offset);
386 : : }
387 : :
388 [ # # ]: 0 : printf("logical sector %s: ", conv(hex, cur));
389 [ # # ]: 0 : printf("block number: %s, ", conv(hex, blk));
390 [ # # ]: 0 : printf("sector offset: %s, ", conv(hex, lsec));
391 [ # # ]: 0 : printf("file offset: %s\n", (offset == DD_BLK_UNUSED ?
392 [ # # ]: 0 : "not allocated" : conv(hex, offset)));
393 : : }
394 : :
395 : : return 0;
396 : : }
397 : :
398 : : static int
399 : 0 : vhd_print_bat(vhd_context_t *vhd, uint64_t block, int count, int hex)
400 : : {
401 : : int i;
402 : : uint64_t cur, offset;
403 : :
404 [ # # ]: 0 : if (check_block_range(vhd, block + count, hex))
405 : : return -ERANGE;
406 : :
407 [ # # ][ # # ]: 0 : for (i = 0; i < count && i < vhd->bat.entries; i++) {
408 : 0 : cur = block + i;
409 : 0 : offset = vhd->bat.bat[cur];
410 : :
411 [ # # ]: 0 : printf("block: %s: ", conv(hex, cur));
412 [ # # ]: 0 : printf("offset: %s\n",
413 : : (offset == DD_BLK_UNUSED ? "not allocated" :
414 [ # # ]: 0 : conv(hex, vhd_sectors_to_bytes(offset))));
415 : : }
416 : :
417 : : return 0;
418 : : }
419 : :
420 : : static int
421 : 0 : vhd_print_bat_str(vhd_context_t *vhd)
422 : : {
423 : : int i, err, total_blocks, bitmap_size;
424 : : char *bitmap;
425 : : ssize_t n;
426 : :
427 : 0 : err = 0;
428 : :
429 [ # # ]: 0 : if (!vhd_type_dynamic(vhd))
430 : : return -EINVAL;
431 : :
432 : 0 : total_blocks = vhd->footer.curr_size / vhd->header.block_size;
433 : 0 : bitmap_size = total_blocks >> 3;
434 [ # # ]: 0 : if (bitmap_size << 3 < total_blocks)
435 : 0 : bitmap_size++;
436 : :
437 : 0 : bitmap = malloc(bitmap_size);
438 [ # # ]: 0 : if (!bitmap)
439 : : return -ENOMEM;
440 : 0 : memset(bitmap, 0, bitmap_size);
441 : :
442 [ # # ]: 0 : for (i = 0; i < total_blocks; i++) {
443 [ # # ]: 0 : if (vhd->bat.bat[i] != DD_BLK_UNUSED)
444 : 0 : set_bit(bitmap, i);
445 : : }
446 : :
447 : 0 : n = write(STDOUT_FILENO, bitmap, bitmap_size);
448 [ # # ]: 0 : if (n < 0)
449 : 0 : err = -errno;
450 : :
451 : 0 : free(bitmap);
452 : :
453 : 0 : return err;
454 : : }
455 : :
456 : : static int
457 : 0 : vhd_print_bitmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
458 : : {
459 : : char *buf;
460 : : int i, err;
461 : : uint64_t cur;
462 : : ssize_t n;
463 : :
464 [ # # ]: 0 : if (check_block_range(vhd, block + count, hex))
465 : 0 : return -ERANGE;
466 : :
467 [ # # ]: 0 : for (i = 0; i < count; i++) {
468 : 0 : cur = block + i;
469 : :
470 [ # # ]: 0 : if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
471 [ # # ]: 0 : printf("block %s not allocated\n", conv(hex, cur));
472 : 0 : continue;
473 : : }
474 : :
475 : 0 : err = vhd_read_bitmap(vhd, cur, &buf);
476 [ # # ]: 0 : if (err)
477 : : goto out;
478 : :
479 : 0 : n = write(STDOUT_FILENO, buf, vhd_sectors_to_bytes(vhd->bm_secs));
480 [ # # ]: 0 : if (n < 0) {
481 : 0 : err = -errno;
482 : 0 : goto out;
483 : : }
484 : :
485 : 0 : free(buf);
486 : : }
487 : :
488 : : err = 0;
489 : : out:
490 : 0 : return err;
491 : : }
492 : :
493 : : static int
494 : 0 : vhd_test_bitmap(vhd_context_t *vhd, uint64_t sector, int count, int hex)
495 : : {
496 : : char *buf;
497 : : uint64_t cur;
498 : : int i, err, bit;
499 : : uint32_t blk, bm_blk, sec;
500 : :
501 [ # # ]: 0 : if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
502 [ # # ]: 0 : printf("sector %s past end of file\n", conv(hex, sector));
503 : 0 : return -ERANGE;
504 : : }
505 : :
506 : 0 : bm_blk = -1;
507 : 0 : buf = NULL;
508 : :
509 [ # # ]: 0 : for (i = 0; i < count; i++) {
510 : 0 : cur = sector + i;
511 : 0 : blk = cur / vhd->spb;
512 : 0 : sec = cur % vhd->spb;
513 : :
514 [ # # ]: 0 : if (blk != bm_blk) {
515 : 0 : bm_blk = blk;
516 : 0 : free(buf);
517 : 0 : buf = NULL;
518 : :
519 [ # # ]: 0 : if (vhd->bat.bat[blk] != DD_BLK_UNUSED) {
520 : 0 : err = vhd_read_bitmap(vhd, blk, &buf);
521 [ # # ]: 0 : if (err)
522 : : goto out;
523 : : }
524 : : }
525 : :
526 [ # # ]: 0 : if (vhd->bat.bat[blk] == DD_BLK_UNUSED)
527 : : bit = 0;
528 : : else
529 : 0 : bit = vhd_bitmap_test(vhd, buf, sec);
530 : :
531 [ # # ]: 0 : printf("block %s: ", conv(hex, blk));
532 [ # # ]: 0 : printf("sec: %s: %d\n", conv(hex, sec), bit);
533 : : }
534 : :
535 : : err = 0;
536 : : out:
537 : 0 : free(buf);
538 : 0 : return err;
539 : : }
540 : :
541 : : static int
542 : 0 : vhd_print_bitmap_extents(vhd_context_t *vhd, uint64_t sector, int count,
543 : : int hex)
544 : : {
545 : : char *buf;
546 : : uint64_t cur;
547 : : int i, err, bit;
548 : : uint32_t blk, bm_blk, sec;
549 : : int64_t s, r;
550 : :
551 [ # # ]: 0 : if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
552 [ # # ]: 0 : printf("sector %s past end of file\n", conv(hex, sector));
553 : 0 : return -ERANGE;
554 : : }
555 : :
556 : 0 : bm_blk = -1;
557 : 0 : buf = NULL;
558 : 0 : s = -1;
559 : 0 : r = 0;
560 : :
561 [ # # ]: 0 : for (i = 0; i < count; i++) {
562 : 0 : cur = sector + i;
563 : 0 : blk = cur / vhd->spb;
564 : 0 : sec = cur % vhd->spb;
565 : :
566 [ # # ]: 0 : if (blk != bm_blk) {
567 : 0 : bm_blk = blk;
568 : 0 : free(buf);
569 : 0 : buf = NULL;
570 : :
571 [ # # ]: 0 : if (vhd->bat.bat[blk] != DD_BLK_UNUSED) {
572 : 0 : err = vhd_read_bitmap(vhd, blk, &buf);
573 [ # # ]: 0 : if (err)
574 : : goto out;
575 : : }
576 : : }
577 : :
578 [ # # ]: 0 : if (vhd->bat.bat[blk] == DD_BLK_UNUSED)
579 : : bit = 0;
580 : : else
581 : 0 : bit = vhd_bitmap_test(vhd, buf, sec);
582 : :
583 [ # # ]: 0 : if (bit) {
584 [ # # ]: 0 : if (r == 0)
585 : 0 : s = cur;
586 : 0 : r++;
587 : : } else {
588 [ # # ]: 0 : if (r > 0) {
589 [ # # ]: 0 : printf("%s ", conv(hex, s));
590 [ # # ]: 0 : printf("%s\n", conv(hex, r));
591 : : }
592 : : r = 0;
593 : : }
594 : : }
595 [ # # ]: 0 : if (r > 0) {
596 [ # # ]: 0 : printf("%s ", conv(hex, s));
597 [ # # ]: 0 : printf("%s\n", conv(hex, r));
598 : : }
599 : :
600 : : err = 0;
601 : : out:
602 : 0 : free(buf);
603 : 0 : return err;
604 : : }
605 : :
606 : : static int
607 : 0 : vhd_print_batmap(vhd_context_t *vhd)
608 : : {
609 : : int err, gcc;
610 : : size_t size;
611 : :
612 : 0 : err = vhd_get_batmap(vhd);
613 [ # # ]: 0 : if (err) {
614 : : printf("failed to read batmap: %d\n", err);
615 : 0 : return err;
616 : : }
617 : :
618 : 0 : size = vhd_sectors_to_bytes(vhd->batmap.header.batmap_size);
619 : 0 : gcc = write(STDOUT_FILENO, vhd->batmap.map, size);
620 : : if (gcc)
621 : : ;
622 : :
623 : 0 : return 0;
624 : : }
625 : :
626 : : static int
627 : 0 : vhd_test_batmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
628 : : {
629 : : int i, err;
630 : : uint64_t cur;
631 : :
632 [ # # ]: 0 : if (check_block_range(vhd, block + count, hex))
633 : : return -ERANGE;
634 : :
635 : 0 : err = vhd_get_batmap(vhd);
636 [ # # ]: 0 : if (err) {
637 : 0 : fprintf(stderr, "failed to get batmap\n");
638 : 0 : return err;
639 : : }
640 : :
641 [ # # ]: 0 : for (i = 0; i < count; i++) {
642 : 0 : cur = block + i;
643 [ # # ]: 0 : fprintf(stderr, "batmap for block %s: %d\n", conv(hex, cur),
644 : : vhd_batmap_test(vhd, &vhd->batmap, cur));
645 : : }
646 : :
647 : : return 0;
648 : : }
649 : :
650 : : static int
651 : 0 : vhd_print_data(vhd_context_t *vhd, uint64_t block, int count, int hex)
652 : : {
653 : : char *buf;
654 : : int i, err;
655 : : uint64_t cur;
656 : :
657 : 0 : err = 0;
658 : :
659 [ # # ]: 0 : if (check_block_range(vhd, block + count, hex))
660 : 0 : return -ERANGE;
661 : :
662 [ # # ]: 0 : for (i = 0; i < count; i++) {
663 : : int gcc;
664 : 0 : cur = block + i;
665 : :
666 [ # # ]: 0 : if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
667 [ # # ]: 0 : printf("block %s not allocated\n", conv(hex, cur));
668 : 0 : continue;
669 : : }
670 : :
671 : 0 : err = vhd_read_block(vhd, cur, &buf);
672 [ # # ]: 0 : if (err)
673 : : break;
674 : :
675 : 0 : gcc = write(STDOUT_FILENO, buf, vhd->header.block_size);
676 : : if (gcc)
677 : : ;
678 : 0 : free(buf);
679 : : }
680 : :
681 : 0 : return err;
682 : : }
683 : :
684 : : static int
685 : 0 : vhd_read_data(vhd_context_t *vhd, uint64_t sec, int count, int hex)
686 : : {
687 : : void *buf;
688 : : uint64_t cur;
689 : : int err, max, secs;
690 : :
691 [ # # ]: 0 : if (vhd_sectors_to_bytes(sec + count) > vhd->footer.curr_size)
692 : 0 : return -ERANGE;
693 : :
694 [ # # ]: 0 : max = MIN(vhd_sectors_to_bytes(count), VHD_BLOCK_SIZE);
695 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, max);
696 [ # # ]: 0 : if (err)
697 : 0 : return -err;
698 : :
699 : : cur = sec;
700 [ # # ]: 0 : while (count) {
701 : : int gcc;
702 : :
703 : 0 : secs = MIN((max >> VHD_SECTOR_SHIFT), count);
704 : 0 : err = vhd_io_read(vhd, buf, cur, secs);
705 [ # # ]: 0 : if (err)
706 : : break;
707 : :
708 : 0 : gcc = write(STDOUT_FILENO, buf, vhd_sectors_to_bytes(secs));
709 : : if (gcc)
710 : : ;
711 : :
712 : 0 : cur += secs;
713 : 0 : count -= secs;
714 : : }
715 : :
716 : 0 : free(buf);
717 : 0 : return err;
718 : : }
719 : :
720 : : static int
721 : 0 : vhd_read_bytes(vhd_context_t *vhd, uint64_t byte, int count, int hex)
722 : : {
723 : : void *buf;
724 : : uint64_t cur;
725 : : int err, max, bytes;
726 : :
727 [ # # ]: 0 : if (byte + count > vhd->footer.curr_size)
728 : 0 : return -ERANGE;
729 : :
730 : 0 : max = MIN(count, VHD_BLOCK_SIZE);
731 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, max);
732 [ # # ]: 0 : if (err)
733 : 0 : return -err;
734 : :
735 : : cur = byte;
736 [ # # ]: 0 : while (count) {
737 : : ssize_t n;
738 : :
739 : 0 : bytes = MIN(max, count);
740 : 0 : err = vhd_io_read_bytes(vhd, buf, bytes, cur);
741 [ # # ]: 0 : if (err)
742 : : break;
743 : :
744 : 0 : n = write(STDOUT_FILENO, buf, bytes);
745 [ # # ]: 0 : if (n < 0) {
746 : 0 : err = -errno;
747 : 0 : break;
748 : : }
749 : :
750 : 0 : cur += bytes;
751 : 0 : count -= bytes;
752 : : }
753 : :
754 : 0 : free(buf);
755 : 0 : return err;
756 : : }
757 : :
758 : : int
759 : 0 : vhd_util_read(int argc, char **argv)
760 : : {
761 : : char *name;
762 : : vhd_context_t vhd;
763 : : int c, err, headers, hex, bat_str, cache, flags;
764 : : uint64_t bat, bitmap, tbitmap, ebitmap, batmap, tbatmap, data, lsec, count, read;
765 : : uint64_t bread;
766 : :
767 : 0 : err = 0;
768 : 0 : hex = 0;
769 : 0 : cache = 0;
770 : 0 : headers = 0;
771 : 0 : bat_str = 0;
772 : 0 : count = 1;
773 : 0 : bat = -1;
774 : 0 : bitmap = -1;
775 : 0 : tbitmap = -1;
776 : 0 : ebitmap = -1;
777 : 0 : batmap = -1;
778 : 0 : tbatmap = -1;
779 : 0 : data = -1;
780 : 0 : lsec = -1;
781 : 0 : read = -1;
782 : 0 : bread = -1;
783 : 0 : name = NULL;
784 : :
785 [ # # ]: 0 : if (!argc || !argv)
786 : : goto usage;
787 : :
788 : 0 : optind = 0;
789 [ # # ]: 0 : while ((c = getopt(argc, argv, "n:pt:b:Bm:i:e:aj:d:c:r:R:xCh")) != -1) {
790 [ # # # # : 0 : switch(c) {
# # # # #
# # # # #
# # # ]
791 : : case 'n':
792 : 0 : name = optarg;
793 : 0 : break;
794 : : case 'p':
795 : : headers = 1;
796 : : break;
797 : : case 'C':
798 : 0 : cache = 1;
799 : 0 : break;
800 : : case 'B':
801 : 0 : bat_str = 1;
802 : 0 : break;
803 : : case 't':
804 : 0 : lsec = strtoul(optarg, NULL, 10);
805 : 0 : break;
806 : : case 'b':
807 : 0 : bat = strtoull(optarg, NULL, 10);
808 : 0 : break;
809 : : case 'm':
810 : 0 : bitmap = strtoull(optarg, NULL, 10);
811 : 0 : break;
812 : : case 'i':
813 : 0 : tbitmap = strtoul(optarg, NULL, 10);
814 : 0 : break;
815 : : case 'e':
816 : 0 : ebitmap = strtoul(optarg, NULL, 10);
817 : 0 : break;
818 : : case 'a':
819 : 0 : batmap = 1;
820 : 0 : break;
821 : : case 'j':
822 : 0 : tbatmap = strtoull(optarg, NULL, 10);
823 : 0 : break;
824 : : case 'd':
825 : 0 : data = strtoull(optarg, NULL, 10);
826 : 0 : break;
827 : : case 'r':
828 : 0 : read = strtoull(optarg, NULL, 10);
829 : 0 : break;
830 : : case 'R':
831 : 0 : bread = strtoull(optarg, NULL, 10);
832 : 0 : break;
833 : : case 'c':
834 : 0 : count = strtoul(optarg, NULL, 10);
835 : 0 : break;
836 : : case 'x':
837 : 0 : hex = 1;
838 : 0 : break;
839 : : case 'h':
840 : : default:
841 : : goto usage;
842 : : }
843 : : }
844 : :
845 [ # # ][ # # ]: 0 : if (!name || optind != argc)
846 : : goto usage;
847 : :
848 : 0 : flags = VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED;
849 [ # # ]: 0 : if (cache)
850 : 0 : flags |= VHD_OPEN_CACHED | VHD_OPEN_FAST;
851 : 0 : err = vhd_open(&vhd, name, flags);
852 [ # # ]: 0 : if (err) {
853 : : printf("Failed to open %s: %d\n", name, err);
854 : 0 : vhd_dump_headers(name, hex);
855 : 0 : return err;
856 : : }
857 : :
858 : 0 : err = vhd_get_bat(&vhd);
859 [ # # ]: 0 : if (err) {
860 : : printf("Failed to get bat for %s: %d\n", name, err);
861 : : goto out;
862 : : }
863 : :
864 [ # # ]: 0 : if (headers)
865 : 0 : vhd_print_headers(&vhd, hex);
866 : :
867 [ # # ]: 0 : if (lsec != -1) {
868 : 0 : err = vhd_print_logical_to_physical(&vhd, lsec, count, hex);
869 [ # # ]: 0 : if (err)
870 : : goto out;
871 : : }
872 : :
873 [ # # ]: 0 : if (bat != -1) {
874 : 0 : err = vhd_print_bat(&vhd, bat, count, hex);
875 [ # # ]: 0 : if (err)
876 : : goto out;
877 : : }
878 : :
879 [ # # ]: 0 : if (bat_str) {
880 : 0 : err = vhd_print_bat_str(&vhd);
881 [ # # ]: 0 : if (err)
882 : : goto out;
883 : : }
884 : :
885 [ # # ]: 0 : if (bitmap != -1) {
886 : 0 : err = vhd_print_bitmap(&vhd, bitmap, count, hex);
887 [ # # ]: 0 : if (err)
888 : : goto out;
889 : : }
890 : :
891 [ # # ]: 0 : if (tbitmap != -1) {
892 : 0 : err = vhd_test_bitmap(&vhd, tbitmap, count, hex);
893 [ # # ]: 0 : if (err)
894 : : goto out;
895 : : }
896 : :
897 [ # # ]: 0 : if (ebitmap != -1) {
898 : 0 : err = vhd_print_bitmap_extents(&vhd, ebitmap, count, hex);
899 [ # # ]: 0 : if (err)
900 : : goto out;
901 : : }
902 : :
903 [ # # ]: 0 : if (batmap != -1) {
904 : 0 : err = vhd_print_batmap(&vhd);
905 [ # # ]: 0 : if (err)
906 : : goto out;
907 : : }
908 : :
909 [ # # ]: 0 : if (tbatmap != -1) {
910 : 0 : err = vhd_test_batmap(&vhd, tbatmap, count, hex);
911 [ # # ]: 0 : if (err)
912 : : goto out;
913 : : }
914 : :
915 [ # # ]: 0 : if (data != -1) {
916 : 0 : err = vhd_print_data(&vhd, data, count, hex);
917 [ # # ]: 0 : if (err)
918 : : goto out;
919 : : }
920 : :
921 [ # # ]: 0 : if (read != -1) {
922 : 0 : err = vhd_read_data(&vhd, read, count, hex);
923 [ # # ]: 0 : if (err)
924 : : goto out;
925 : : }
926 : :
927 [ # # ]: 0 : if (bread != -1) {
928 : 0 : err = vhd_read_bytes(&vhd, bread, count, hex);
929 [ # # ]: 0 : if (err)
930 : : goto out;
931 : : }
932 : :
933 : : err = 0;
934 : :
935 : : out:
936 : 0 : vhd_close(&vhd);
937 : : return err;
938 : :
939 : : usage:
940 : : printf("options:\n"
941 : : "-h help\n"
942 : : "-n name\n"
943 : : "-p print VHD headers\n"
944 : : "-t sec translate logical sector to VHD location\n"
945 : : "-b blk print bat entry\n"
946 : : "-B print entire bat as a bitmap\n"
947 : : "-m blk print bitmap\n"
948 : : "-i sec test bitmap for logical sector\n"
949 : : "-e sec output extent list of allocated logical sectors\n"
950 : : "-a print batmap\n"
951 : : "-j blk test batmap for block\n"
952 : : "-d blk print data\n"
953 : : "-c num num units\n"
954 : : "-r sec read num sectors at sec\n"
955 : : "-R byte read num bytes at byte\n"
956 : : "-x print in hex\n");
957 : : return EINVAL;
958 : : }
|