LCOV - code coverage report
Current view: top level - vhd/lib - vhd-util-read.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 411 0.0 %
Date: 2025-03-04 17:26:00 Functions: 0 25 0.0 %
Branches: 0 315 0.0 %

           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                 :            : }

Generated by: LCOV version 1.13