ia64/xen-unstable

view tools/blktap2/vhd/lib/vhd-util-read.c @ 19833:f3a909c8e8e6

blktap2: A final few NetBSD fixes

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jun 24 15:24:53 2009 +0100 (2009-06-24)
parents f1fec38c8228
children
line source
1 /* Copyright (c) 2008, XenSource Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of XenSource Inc. nor the names of its contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <stdio.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <inttypes.h>
34 #include "libvhd.h"
35 #include "vhd-util.h"
37 #define nsize 15
38 static char nbuf[nsize];
40 static inline char *
41 __xconv(uint64_t num)
42 {
43 snprintf(nbuf, nsize, "%#" PRIx64 , num);
44 return nbuf;
45 }
47 static inline char *
48 __dconv(uint64_t num)
49 {
50 snprintf(nbuf, nsize, "%" PRIu64, num);
51 return nbuf;
52 }
54 #define conv(hex, num) \
55 (hex ? __xconv((uint64_t)num) : __dconv((uint64_t)num))
57 static void
58 vhd_print_header(vhd_context_t *vhd, vhd_header_t *h, int hex)
59 {
60 int err;
61 uint32_t cksm;
62 char uuid[39], time_str[26], cookie[9], out[512], *name;
64 printf("VHD Header Summary:\n-------------------\n");
66 snprintf(cookie, sizeof(cookie), "%s", h->cookie);
67 printf("Cookie : %s\n", cookie);
69 printf("Data offset (unusd) : %s\n", conv(hex, h->data_offset));
70 printf("Table offset : %s\n", conv(hex, h->table_offset));
71 printf("Header version : 0x%08x\n", h->hdr_ver);
72 printf("Max BAT size : %s\n", conv(hex, h->max_bat_size));
73 printf("Block size : %s ", conv(hex, h->block_size));
74 printf("(%s MB)\n", conv(hex, h->block_size >> 20));
76 err = vhd_header_decode_parent(vhd, h, &name);
77 printf("Parent name : %s\n",
78 (err ? "failed to read name" : name));
79 free(name);
81 blk_uuid_to_string(&h->prt_uuid, uuid, sizeof(uuid));
82 printf("Parent UUID : %s\n", uuid);
84 vhd_time_to_string(h->prt_ts, time_str);
85 printf("Parent timestamp : %s\n", time_str);
87 cksm = vhd_checksum_header(h);
88 printf("Checksum : 0x%x|0x%x (%s)\n", h->checksum, cksm,
89 h->checksum == cksm ? "Good!" : "Bad!");
90 printf("\n");
91 }
93 static void
94 vhd_print_footer(vhd_footer_t *f, int hex)
95 {
96 uint64_t c, h, s;
97 uint32_t ff_maj, ff_min, cr_maj, cr_min, cksm, cksm_save;
98 char time_str[26], creator[5], uuid[39], cookie[9];
100 printf("VHD Footer Summary:\n-------------------\n");
102 snprintf(cookie, sizeof(cookie), "%s", f->cookie);
103 printf("Cookie : %s\n", cookie);
105 printf("Features : (0x%08x) %s%s\n", f->features,
106 (f->features & HD_TEMPORARY) ? "<TEMP>" : "",
107 (f->features & HD_RESERVED) ? "<RESV>" : "");
109 ff_maj = f->ff_version >> 16;
110 ff_min = f->ff_version & 0xffff;
111 printf("File format version : Major: %d, Minor: %d\n",
112 ff_maj, ff_min);
114 printf("Data offset : %s\n", conv(hex, f->data_offset));
116 vhd_time_to_string(f->timestamp, time_str);
117 printf("Timestamp : %s\n", time_str);
119 memcpy(creator, f->crtr_app, 4);
120 creator[4] = '\0';
121 printf("Creator Application : '%s'\n", creator);
123 cr_maj = f->crtr_ver >> 16;
124 cr_min = f->crtr_ver & 0xffff;
125 printf("Creator version : Major: %d, Minor: %d\n",
126 cr_maj, cr_min);
128 printf("Creator OS : %s\n",
129 ((f->crtr_os == HD_CR_OS_WINDOWS) ? "Windows" :
130 ((f->crtr_os == HD_CR_OS_MACINTOSH) ? "Macintosh" :
131 "Unknown!")));
133 printf("Original disk size : %s MB ", conv(hex, f->orig_size >> 20));
134 printf("(%s Bytes)\n", conv(hex, f->orig_size));
136 printf("Current disk size : %s MB ", conv(hex, f->curr_size >> 20));
137 printf("(%s Bytes)\n", conv(hex, f->curr_size));
139 c = f->geometry >> 16;
140 h = (f->geometry & 0x0000FF00) >> 8;
141 s = f->geometry & 0x000000FF;
142 printf("Geometry : Cyl: %s, ", conv(hex, c));
143 printf("Hds: %s, ", conv(hex, h));
144 printf("Sctrs: %s\n", conv(hex, s));
145 printf(" : = %s MB ", conv(hex, (c * h * s) >> 11));
146 printf("(%s Bytes)\n", conv(hex, c * h * s << 9));
148 printf("Disk type : %s\n",
149 f->type <= HD_TYPE_MAX ?
150 HD_TYPE_STR[f->type] : "Unknown type!\n");
152 cksm = vhd_checksum_footer(f);
153 printf("Checksum : 0x%x|0x%x (%s)\n", f->checksum, cksm,
154 f->checksum == cksm ? "Good!" : "Bad!");
156 blk_uuid_to_string(&f->uuid, uuid, sizeof(uuid));
157 printf("UUID : %s\n", uuid);
159 printf("Saved state : %s\n", f->saved == 0 ? "No" : "Yes");
160 printf("Hidden : %d\n", f->hidden);
161 printf("\n");
162 }
164 static inline char *
165 code_name(uint32_t code)
166 {
167 switch(code) {
168 case PLAT_CODE_NONE:
169 return "PLAT_CODE_NONE";
170 case PLAT_CODE_WI2R:
171 return "PLAT_CODE_WI2R";
172 case PLAT_CODE_WI2K:
173 return "PLAT_CODE_WI2K";
174 case PLAT_CODE_W2RU:
175 return "PLAT_CODE_W2RU";
176 case PLAT_CODE_W2KU:
177 return "PLAT_CODE_W2KU";
178 case PLAT_CODE_MAC:
179 return "PLAT_CODE_MAC";
180 case PLAT_CODE_MACX:
181 return "PLAT_CODE_MACX";
182 default:
183 return "UNKOWN";
184 }
185 }
187 static void
188 vhd_print_parent(vhd_context_t *vhd, vhd_parent_locator_t *loc)
189 {
190 int err;
191 char *buf;
193 err = vhd_parent_locator_read(vhd, loc, &buf);
194 if (err) {
195 printf("failed to read parent name\n");
196 return;
197 }
199 printf(" decoded name : %s\n", buf);
200 }
202 static void
203 vhd_print_parent_locators(vhd_context_t *vhd, int hex)
204 {
205 int i, n;
206 vhd_parent_locator_t *loc;
208 printf("VHD Parent Locators:\n--------------------\n");
210 n = sizeof(vhd->header.loc) / sizeof(struct prt_loc);
211 for (i = 0; i < n; i++) {
212 loc = &vhd->header.loc[i];
214 if (loc->code == PLAT_CODE_NONE)
215 continue;
217 printf("locator: : %d\n", i);
218 printf(" code : %s\n",
219 code_name(loc->code));
220 printf(" data_space : %s\n",
221 conv(hex, loc->data_space));
222 printf(" data_length : %s\n",
223 conv(hex, loc->data_len));
224 printf(" data_offset : %s\n",
225 conv(hex, loc->data_offset));
226 vhd_print_parent(vhd, loc);
227 printf("\n");
228 }
229 }
231 static void
232 vhd_print_batmap_header(vhd_batmap_t *batmap, int hex)
233 {
234 uint32_t cksm;
236 printf("VHD Batmap Summary:\n-------------------\n");
237 printf("Batmap offset : %s\n",
238 conv(hex, batmap->header.batmap_offset));
239 printf("Batmap size (secs) : %s\n",
240 conv(hex, batmap->header.batmap_size));
241 printf("Batmap version : 0x%08x\n",
242 batmap->header.batmap_version);
244 cksm = vhd_checksum_batmap(batmap);
245 printf("Checksum : 0x%x|0x%x (%s)\n",
246 batmap->header.checksum, cksm,
247 (batmap->header.checksum == cksm ? "Good!" : "Bad!"));
248 printf("\n");
249 }
251 static inline int
252 check_block_range(vhd_context_t *vhd, uint64_t block, int hex)
253 {
254 if (block > vhd->header.max_bat_size) {
255 fprintf(stderr, "block %s past end of file\n",
256 conv(hex, block));
257 return -ERANGE;
258 }
260 return 0;
261 }
263 static int
264 vhd_print_headers(vhd_context_t *vhd, int hex)
265 {
266 int err;
268 vhd_print_footer(&vhd->footer, hex);
270 if (vhd_type_dynamic(vhd)) {
271 vhd_print_header(vhd, &vhd->header, hex);
273 if (vhd->footer.type == HD_TYPE_DIFF)
274 vhd_print_parent_locators(vhd, hex);
276 if (vhd_has_batmap(vhd)) {
277 err = vhd_get_batmap(vhd);
278 if (err) {
279 printf("failed to get batmap header\n");
280 return err;
281 }
283 vhd_print_batmap_header(&vhd->batmap, hex);
284 }
285 }
287 return 0;
288 }
290 static int
291 vhd_dump_headers(const char *name, int hex)
292 {
293 vhd_context_t vhd;
295 libvhd_set_log_level(1);
296 memset(&vhd, 0, sizeof(vhd));
298 printf("\n%s appears invalid; dumping headers\n\n", name);
300 vhd.fd = open(name, O_DIRECT | O_LARGEFILE | O_RDONLY);
301 if (vhd.fd == -1)
302 return -errno;
304 vhd.file = strdup(name);
306 vhd_read_footer(&vhd, &vhd.footer);
307 vhd_read_header(&vhd, &vhd.header);
309 vhd_print_footer(&vhd.footer, hex);
310 vhd_print_header(&vhd, &vhd.header, hex);
312 close(vhd.fd);
313 free(vhd.file);
315 return 0;
316 }
318 static int
319 vhd_print_logical_to_physical(vhd_context_t *vhd,
320 uint64_t sector, int count, int hex)
321 {
322 int i;
323 uint32_t blk, lsec;
324 uint64_t cur, offset;
326 if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
327 fprintf(stderr, "sector %s past end of file\n",
328 conv(hex, sector + count));
329 return -ERANGE;
330 }
332 for (i = 0; i < count; i++) {
333 cur = sector + i;
334 blk = cur / vhd->spb;
335 lsec = cur % vhd->spb;
336 offset = vhd->bat.bat[blk];
338 if (offset != DD_BLK_UNUSED) {
339 offset += lsec + 1;
340 offset = vhd_sectors_to_bytes(offset);
341 }
343 printf("logical sector %s: ", conv(hex, cur));
344 printf("block number: %s, ", conv(hex, blk));
345 printf("sector offset: %s, ", conv(hex, lsec));
346 printf("file offset: %s\n", (offset == DD_BLK_UNUSED ?
347 "not allocated" : conv(hex, offset)));
348 }
350 return 0;
351 }
353 static int
354 vhd_print_bat(vhd_context_t *vhd, uint64_t block, int count, int hex)
355 {
356 int i;
357 uint64_t cur, offset;
359 if (check_block_range(vhd, block + count, hex))
360 return -ERANGE;
362 for (i = 0; i < count; i++) {
363 cur = block + i;
364 offset = vhd->bat.bat[cur];
366 printf("block: %s: ", conv(hex, cur));
367 printf("offset: %s\n",
368 (offset == DD_BLK_UNUSED ? "not allocated" :
369 conv(hex, vhd_sectors_to_bytes(offset))));
370 }
372 return 0;
373 }
375 static inline void
376 write_full(int fd, void* buf, size_t count)
377 {
378 ssize_t num_written = 0;
379 if (!buf) return;
382 while(count > 0) {
384 num_written = write(fd, buf, count);
385 if (num_written == -1) {
386 if (errno == EINTR)
387 continue;
388 else
389 return;
390 }
392 count -= num_written;
393 buf += num_written;
394 }
395 }
397 static int
398 vhd_print_bitmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
399 {
400 char *buf;
401 int i, err;
402 uint64_t cur;
404 if (check_block_range(vhd, block + count, hex))
405 return -ERANGE;
407 for (i = 0; i < count; i++) {
408 cur = block + i;
410 if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
411 printf("block %s not allocated\n", conv(hex, cur));
412 continue;
413 }
415 err = vhd_read_bitmap(vhd, cur, &buf);
416 if (err)
417 goto out;
419 write_full(STDOUT_FILENO, buf,
420 vhd_sectors_to_bytes(vhd->bm_secs));
421 free(buf);
422 }
424 err = 0;
425 out:
426 return err;
427 }
429 static int
430 vhd_test_bitmap(vhd_context_t *vhd, uint64_t sector, int count, int hex)
431 {
432 char *buf;
433 uint64_t cur;
434 int i, err, bit;
435 uint32_t blk, bm_blk, sec;
437 if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
438 printf("sector %s past end of file\n", conv(hex, sector));
439 return -ERANGE;
440 }
442 bm_blk = -1;
443 buf = NULL;
445 for (i = 0; i < count; i++) {
446 cur = sector + i;
447 blk = cur / vhd->spb;
448 sec = cur % vhd->spb;
450 if (blk != bm_blk) {
451 bm_blk = blk;
452 free(buf);
453 buf = NULL;
455 if (vhd->bat.bat[blk] != DD_BLK_UNUSED) {
456 err = vhd_read_bitmap(vhd, blk, &buf);
457 if (err)
458 goto out;
459 }
460 }
462 if (vhd->bat.bat[blk] == DD_BLK_UNUSED)
463 bit = 0;
464 else
465 bit = vhd_bitmap_test(vhd, buf, blk);
467 print:
468 printf("block %s: ", conv(hex, blk));
469 printf("sec: %s: %d\n", conv(hex, sec), bit);
470 }
472 err = 0;
473 out:
474 free(buf);
475 return err;
476 }
478 static int
479 vhd_print_batmap(vhd_context_t *vhd)
480 {
481 int err;
482 size_t size;
484 err = vhd_get_batmap(vhd);
485 if (err) {
486 printf("failed to read batmap: %d\n", err);
487 return err;
488 }
490 size = vhd_sectors_to_bytes(vhd->batmap.header.batmap_size);
491 write_full(STDOUT_FILENO, vhd->batmap.map, size);
493 return 0;
494 }
496 static int
497 vhd_test_batmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
498 {
499 int i, err;
500 uint64_t cur;
502 if (check_block_range(vhd, block + count, hex))
503 return -ERANGE;
505 err = vhd_get_batmap(vhd);
506 if (err) {
507 fprintf(stderr, "failed to get batmap\n");
508 return err;
509 }
511 for (i = 0; i < count; i++) {
512 cur = block + i;
513 fprintf(stderr, "batmap for block %s: %d\n", conv(hex, cur),
514 vhd_batmap_test(vhd, &vhd->batmap, cur));
515 }
517 return 0;
518 }
520 static int
521 vhd_print_data(vhd_context_t *vhd, uint64_t block, int count, int hex)
522 {
523 char *buf;
524 int i, err;
525 uint64_t cur;
527 err = 0;
529 if (check_block_range(vhd, block + count, hex))
530 return -ERANGE;
532 for (i = 0; i < count; i++) {
533 cur = block + i;
535 if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
536 printf("block %s not allocated\n", conv(hex, cur));
537 continue;
538 }
540 err = vhd_read_block(vhd, cur, &buf);
541 if (err)
542 break;
544 write_full(STDOUT_FILENO, buf, vhd->header.block_size);
545 free(buf);
546 }
548 return err;
549 }
551 static int
552 vhd_read_data(vhd_context_t *vhd, uint64_t sec, int count, int hex)
553 {
554 char *buf;
555 uint64_t cur;
556 int err, max, secs;
558 if (vhd_sectors_to_bytes(sec + count) > vhd->footer.curr_size)
559 return -ERANGE;
561 max = MIN(vhd_sectors_to_bytes(count), VHD_BLOCK_SIZE);
562 err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, max);
563 if (err)
564 return -err;
566 cur = sec;
567 while (count) {
568 secs = MIN((max >> VHD_SECTOR_SHIFT), count);
569 err = vhd_io_read(vhd, buf, cur, secs);
570 if (err)
571 break;
573 write_full(STDOUT_FILENO, buf, vhd_sectors_to_bytes(secs));
575 cur += secs;
576 count -= secs;
577 }
579 free(buf);
580 return err;
581 }
583 int
584 vhd_util_read(int argc, char **argv)
585 {
586 char *name;
587 vhd_context_t vhd;
588 int c, err, headers, hex;
589 uint64_t bat, bitmap, tbitmap, batmap, tbatmap, data, lsec, count, read;
591 err = 0;
592 hex = 0;
593 headers = 0;
594 count = 1;
595 bat = -1;
596 bitmap = -1;
597 tbitmap = -1;
598 batmap = -1;
599 tbatmap = -1;
600 data = -1;
601 lsec = -1;
602 read = -1;
603 name = NULL;
605 if (!argc || !argv)
606 goto usage;
608 optind = 0;
609 while ((c = getopt(argc, argv, "n:pt:b:m:i:aj:d:c:r:xh")) != -1) {
610 switch(c) {
611 case 'n':
612 name = optarg;
613 break;
614 case 'p':
615 headers = 1;
616 break;
617 case 't':
618 lsec = strtoul(optarg, NULL, 10);
619 break;
620 case 'b':
621 bat = strtoull(optarg, NULL, 10);
622 break;
623 case 'm':
624 bitmap = strtoull(optarg, NULL, 10);
625 break;
626 case 'i':
627 tbitmap = strtoul(optarg, NULL, 10);
628 break;
629 case 'a':
630 batmap = 1;
631 break;
632 case 'j':
633 tbatmap = strtoull(optarg, NULL, 10);
634 break;
635 case 'd':
636 data = strtoull(optarg, NULL, 10);
637 break;
638 case 'r':
639 read = strtoull(optarg, NULL, 10);
640 break;
641 case 'c':
642 count = strtoul(optarg, NULL, 10);
643 break;
644 case 'x':
645 hex = 1;
646 break;
647 case 'h':
648 default:
649 goto usage;
650 }
651 }
653 if (!name || optind != argc)
654 goto usage;
656 err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
657 if (err) {
658 printf("Failed to open %s: %d\n", name, err);
659 vhd_dump_headers(name, hex);
660 return err;
661 }
663 err = vhd_get_bat(&vhd);
664 if (err) {
665 printf("Failed to get bat for %s: %d\n", name, err);
666 goto out;
667 }
669 if (headers)
670 vhd_print_headers(&vhd, hex);
672 if (lsec != -1) {
673 err = vhd_print_logical_to_physical(&vhd, lsec, count, hex);
674 if (err)
675 goto out;
676 }
678 if (bat != -1) {
679 err = vhd_print_bat(&vhd, bat, count, hex);
680 if (err)
681 goto out;
682 }
684 if (bitmap != -1) {
685 err = vhd_print_bitmap(&vhd, bitmap, count, hex);
686 if (err)
687 goto out;
688 }
690 if (tbitmap != -1) {
691 err = vhd_test_bitmap(&vhd, tbitmap, count, hex);
692 if (err)
693 goto out;
694 }
696 if (batmap != -1) {
697 err = vhd_print_batmap(&vhd);
698 if (err)
699 goto out;
700 }
702 if (tbatmap != -1) {
703 err = vhd_test_batmap(&vhd, tbatmap, count, hex);
704 if (err)
705 goto out;
706 }
708 if (data != -1) {
709 err = vhd_print_data(&vhd, data, count, hex);
710 if (err)
711 goto out;
712 }
714 if (read != -1) {
715 err = vhd_read_data(&vhd, read, count, hex);
716 if (err)
717 goto out;
718 }
720 err = 0;
722 out:
723 vhd_close(&vhd);
724 return err;
726 usage:
727 printf("options:\n"
728 "-h help\n"
729 "-n name\n"
730 "-p print VHD headers\n"
731 "-t sec translate logical sector to VHD location\n"
732 "-b blk print bat entry\n"
733 "-m blk print bitmap\n"
734 "-i sec test bitmap for logical sector\n"
735 "-a print batmap\n"
736 "-j blk test batmap for block\n"
737 "-d blk print data\n"
738 "-c num num units\n"
739 "-r sec read num sectors at sec\n"
740 "-x print in hex\n");
741 return EINVAL;
742 }