LCOV - code coverage report
Current view: top level - vhd/lib - vhd-util-check.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 494 0.0 %
Date: 2024-12-18 23:41:32 Functions: 0 27 0.0 %
Branches: 0 449 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 <time.h>
      36                 :            : #include <stdio.h>
      37                 :            : #include <errno.h>
      38                 :            : #include <fcntl.h>
      39                 :            : #include <stdlib.h>
      40                 :            : #include <unistd.h>
      41                 :            : #include <libgen.h>
      42                 :            : #include <inttypes.h>
      43                 :            : #include <sys/stat.h>
      44                 :            : 
      45                 :            : #include "list.h"
      46                 :            : #include "libvhd.h"
      47                 :            : #include "vhd-util.h"
      48                 :            : 
      49                 :            : // allow the VHD timestamp to be at most this many seconds into the future to 
      50                 :            : // account for time skew with NFS servers
      51                 :            : #define TIMESTAMP_MAX_SLACK 1800
      52                 :            : 
      53                 :            : struct vhd_util_check_options {
      54                 :            :         char                             ignore_footer;
      55                 :            :         char                             ignore_parent_uuid;
      56                 :            :         char                             ignore_timestamps;
      57                 :            :         char                             check_data;
      58                 :            :         char                             no_check_bat;
      59                 :            :         char                             collect_stats;
      60                 :            : };
      61                 :            : 
      62                 :            : struct vhd_util_check_stats {
      63                 :            :         char                            *name;
      64                 :            :         char                            *bitmap;
      65                 :            :         uint64_t                         secs_total;
      66                 :            :         uint64_t                         secs_allocated;
      67                 :            :         uint64_t                         secs_written;
      68                 :            :         struct list_head                 next;
      69                 :            : };
      70                 :            : 
      71                 :            : struct vhd_util_check_ctx {
      72                 :            :         struct vhd_util_check_options    opts;
      73                 :            :         struct list_head                 stats;
      74                 :            :         int                              primary_footer_missing;
      75                 :            : };
      76                 :            : 
      77                 :            : #define ctx_cur_stats(ctx) \
      78                 :            :         list_entry((ctx)->stats.next, struct vhd_util_check_stats, next)
      79                 :            : 
      80                 :            : static inline int
      81                 :            : test_bit_u64(volatile char *addr, uint64_t nr)
      82                 :            : {
      83                 :          0 :         return ((addr[nr >> 3] << (nr & 7)) & 0x80) != 0;
      84                 :            : }
      85                 :            : 
      86                 :            : static inline void
      87                 :            : set_bit_u64(volatile char *addr, uint64_t nr)
      88                 :            : {
      89                 :          0 :         addr[nr >> 3] |= (0x80 >> (nr & 7));
      90                 :            : }
      91                 :            : 
      92                 :            : static void
      93                 :            : vhd_util_check_stats_init(struct vhd_util_check_ctx *ctx)
      94                 :            : {
      95                 :          0 :         memset(&ctx->stats, 0, sizeof(ctx->stats));
      96                 :          0 :         INIT_LIST_HEAD(&ctx->stats);
      97                 :            : }
      98                 :            : 
      99                 :            : static void
     100                 :          0 : vhd_util_check_stats_free_one(struct vhd_util_check_stats *stats)
     101                 :            : {
     102         [ #  # ]:          0 :         if (stats) {
     103                 :          0 :                 free(stats->name);
     104                 :          0 :                 free(stats->bitmap);
     105                 :          0 :                 free(stats);
     106                 :            :         }
     107                 :          0 : }
     108                 :            : 
     109                 :            : static int
     110                 :          0 : vhd_util_check_stats_alloc_one(struct vhd_util_check_ctx *ctx,
     111                 :            :                                vhd_context_t *vhd)
     112                 :            : {
     113                 :            :         int size;
     114                 :            :         struct vhd_util_check_stats *stats;
     115                 :            : 
     116                 :          0 :         stats = calloc(1, sizeof(*stats));
     117         [ #  # ]:          0 :         if (!stats)
     118                 :            :                 goto fail;
     119                 :            : 
     120                 :          0 :         stats->name = strdup(vhd->file);
     121         [ #  # ]:          0 :         if (!stats->name)
     122                 :            :                 goto fail;
     123                 :            : 
     124                 :          0 :         stats->secs_total = (uint64_t)vhd->spb * vhd->header.max_bat_size;
     125                 :          0 :         size = (stats->secs_total + 7) >> 3;
     126                 :          0 :         stats->bitmap = calloc(1, size);
     127         [ #  # ]:          0 :         if (!stats->bitmap)
     128                 :            :                 goto fail;
     129                 :            : 
     130                 :          0 :         INIT_LIST_HEAD(&stats->next);
     131                 :          0 :         list_add(&stats->next, &ctx->stats);
     132                 :            : 
     133                 :          0 :         return 0;
     134                 :            : 
     135                 :            : fail:
     136                 :          0 :         vhd_util_check_stats_free_one(stats);
     137                 :          0 :         printf("failed to allocate stats for %s\n", vhd->file);
     138                 :          0 :         return -ENOMEM;
     139                 :            : }
     140                 :            : 
     141                 :            : static void
     142                 :          0 : vhd_util_check_stats_free(struct vhd_util_check_ctx *ctx)
     143                 :            : {
     144                 :            :         struct vhd_util_check_stats *stats, *tmp;
     145                 :            : 
     146         [ #  # ]:          0 :         list_for_each_entry_safe(stats, tmp, &ctx->stats, next) {
     147                 :          0 :                 list_del_init(&stats->next);
     148                 :          0 :                 vhd_util_check_stats_free_one(stats);
     149                 :            :         }
     150                 :          0 : }
     151                 :            : 
     152                 :            : static inline float
     153                 :            : pct(uint64_t num, uint64_t den)
     154                 :            : {
     155 [ #  # ][ #  # ]:          0 :         return (!den ? 0.0 : (((float)num / (float)den)) * 100.0);
         [ #  # ][ #  # ]
     156                 :            : }
     157                 :            : 
     158                 :            : static inline char *
     159                 :          0 : name(const char *path)
     160                 :            : {
     161                 :          0 :         char *p = strrchr(path, '/');
     162 [ #  # ][ #  # ]:          0 :         if (p && (p - path) == strlen(path))
     163                 :          0 :                 p = strrchr(--p, '/');
     164         [ #  # ]:          0 :         return (char *)(p ? ++p : path);
     165                 :            : }
     166                 :            : 
     167                 :            : static void
     168                 :          0 : vhd_util_check_stats_print(struct vhd_util_check_ctx *ctx)
     169                 :            : {
     170                 :            :         char *bitmap;
     171                 :            :         uint64_t secs;
     172                 :            :         struct vhd_util_check_stats *head, *cur, *prev;
     173                 :            : 
     174         [ #  # ]:          0 :         if (list_empty(&ctx->stats))
     175                 :            :                 return;
     176                 :            : 
     177                 :          0 :         head = list_entry(ctx->stats.next, struct vhd_util_check_stats, next);
     178                 :          0 :         printf("%s: secs allocated: 0x%"PRIx64" secs written: 0x%"PRIx64" (%.2f%%)\n",
     179                 :          0 :                name(head->name), head->secs_allocated, head->secs_written,
     180                 :          0 :                pct(head->secs_written, head->secs_allocated));
     181                 :            : 
     182         [ #  # ]:          0 :         if (list_is_last(&head->next, &ctx->stats))
     183                 :            :                 return;
     184                 :            : 
     185                 :          0 :         secs = head->secs_total;
     186                 :            : 
     187                 :          0 :         bitmap = malloc((secs + 7) >> 3);
     188         [ #  # ]:          0 :         if (!bitmap) {
     189                 :            :                 printf("failed to allocate bitmap\n");
     190                 :            :                 return;
     191                 :            :         }
     192                 :          0 :         memcpy(bitmap, head->bitmap, ((secs + 7) >> 3));
     193                 :            : 
     194                 :          0 :         cur = prev = head;
     195         [ #  # ]:          0 :         while (!list_is_last(&cur->next, &ctx->stats)) {
     196                 :          0 :                 uint64_t i, up = 0, uc = 0;
     197                 :            : 
     198                 :          0 :                 cur = list_entry(cur->next.next,
     199                 :            :                                  struct vhd_util_check_stats, next);
     200                 :            : 
     201         [ #  # ]:          0 :                 for (i = 0; i < secs; i++) {
     202         [ #  # ]:          0 :                         if (test_bit_u64(cur->bitmap, i)) {
     203         [ #  # ]:          0 :                                 if (!test_bit_u64(prev->bitmap, i))
     204                 :          0 :                                         up++; /* sector is unique wrt parent */
     205                 :            : 
     206         [ #  # ]:          0 :                                 if (!test_bit_u64(bitmap, i))
     207                 :          0 :                                         uc++; /* sector is unique wrt chain */
     208                 :            : 
     209                 :            :                                 set_bit_u64(bitmap, i);
     210                 :            :                         }
     211                 :            :                 }
     212                 :            : 
     213                 :          0 :                 printf("%s: secs allocated: 0x%"PRIx64" secs written: 0x%"PRIx64
     214                 :            :                        " (%.2f%%) secs not in parent: 0x%"PRIx64" (%.2f%%)"
     215                 :            :                        " secs not in ancestors: 0x%"PRIx64" (%.2f%%)\n",
     216                 :          0 :                        name(cur->name), cur->secs_allocated, cur->secs_written,
     217                 :          0 :                        pct(cur->secs_written, cur->secs_allocated),
     218                 :          0 :                        up, pct(up, cur->secs_written),
     219                 :          0 :                        uc, pct(uc, cur->secs_written));
     220                 :            : 
     221                 :          0 :                 prev = cur;
     222                 :            :         }
     223                 :            : 
     224                 :          0 :         free(bitmap);
     225                 :            : }
     226                 :            : 
     227                 :            : static int
     228                 :            : vhd_util_check_zeros(void *buf, size_t size)
     229                 :            : {
     230                 :            :         int i;
     231                 :            :         char *p;
     232                 :            : 
     233                 :          0 :         p = buf;
     234 [ #  # ][ #  # ]:          0 :         for (i = 0; i < size; i++)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     235 [ #  # ][ #  # ]:          0 :                 if (p[i])
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     236                 :            :                         return i;
     237                 :            : 
     238                 :            :         return 0;
     239                 :            : }
     240                 :            : 
     241                 :            : static char *
     242                 :          0 : vhd_util_check_validate_footer(struct vhd_util_check_ctx *ctx,
     243                 :            :                                vhd_footer_t *footer)
     244                 :            : {
     245                 :            :         int size;
     246                 :            :         uint32_t checksum;
     247                 :            : 
     248                 :          0 :         size = sizeof(footer->cookie);
     249         [ #  # ]:          0 :         if (memcmp(footer->cookie, HD_COOKIE, size))
     250                 :            :                 return "invalid cookie";
     251                 :            : 
     252                 :          0 :         checksum = vhd_checksum_footer(footer);
     253         [ #  # ]:          0 :         if (checksum != footer->checksum) {
     254 [ #  # ][ #  # ]:          0 :                 if (footer->hidden &&
     255         [ #  # ]:          0 :                     !strncmp(footer->crtr_app, "tap", 3) &&
     256                 :          0 :                     (footer->crtr_ver == VHD_VERSION(0, 1) ||
     257                 :            :                      footer->crtr_ver == VHD_VERSION(1, 1))) {
     258                 :          0 :                         char tmp = footer->hidden;
     259                 :          0 :                         footer->hidden = 0;
     260                 :          0 :                         checksum = vhd_checksum_footer(footer);
     261                 :          0 :                         footer->hidden = tmp;
     262                 :            : 
     263         [ #  # ]:          0 :                         if (checksum == footer->checksum)
     264                 :            :                                 goto ok;
     265                 :            :                 }
     266                 :            : 
     267                 :            :                 return "invalid checksum";
     268                 :            :         }
     269                 :            : 
     270                 :            : ok:
     271         [ #  # ]:          0 :         if (!(footer->features & HD_RESERVED))
     272                 :            :                 return "invalid 'reserved' feature";
     273                 :            : 
     274         [ #  # ]:          0 :         if (footer->features & ~(HD_TEMPORARY | HD_RESERVED))
     275                 :            :                 return "invalid extra features";
     276                 :            : 
     277         [ #  # ]:          0 :         if (footer->ff_version != HD_FF_VERSION)
     278                 :            :                 return "invalid file format version";
     279                 :            : 
     280         [ #  # ]:          0 :         if (footer->type != HD_TYPE_DYNAMIC &&
     281         [ #  # ]:          0 :             footer->type != HD_TYPE_DIFF    &&
     282                 :          0 :             footer->data_offset != ~(0ULL))
     283                 :            :                 return "invalid data offset";
     284                 :            : 
     285         [ #  # ]:          0 :         if (!ctx->opts.ignore_timestamps) {
     286                 :          0 :                 uint32_t now = vhd_time(time(NULL));
     287         [ #  # ]:          0 :                 if (footer->timestamp > now + TIMESTAMP_MAX_SLACK)
     288                 :            :                         return "creation time in future";
     289                 :            :         }
     290                 :            : 
     291 [ #  # ][ #  # ]:          0 :         if (!strncmp(footer->crtr_app, "tap", 3) &&
     292                 :          0 :             footer->crtr_ver > VHD_CURRENT_VERSION)
     293                 :            :                 return "unsupported tap creator version";
     294                 :            : 
     295         [ #  # ]:          0 :         if (vhd_chs(footer->curr_size) < footer->geometry)
     296                 :            :                 return "geometry too large";
     297                 :            : 
     298         [ #  # ]:          0 :         if (footer->type != HD_TYPE_FIXED   &&
     299                 :          0 :             footer->type != HD_TYPE_DYNAMIC &&
     300                 :            :             footer->type != HD_TYPE_DIFF)
     301                 :            :                 return "invalid type";
     302                 :            : 
     303         [ #  # ]:          0 :         if (footer->saved && footer->saved != 1)
     304                 :            :                 return "invalid 'saved' state";
     305                 :            : 
     306         [ #  # ]:          0 :         if (footer->hidden && footer->hidden != 1)
     307                 :            :                 return "invalid 'hidden' state";
     308                 :            : 
     309         [ #  # ]:          0 :         if (vhd_util_check_zeros(footer->reserved,
     310                 :            :                                  sizeof(footer->reserved)))
     311                 :            :                 return "invalid 'reserved' bits";
     312                 :            : 
     313         [ #  # ]:          0 :         if (uuid_is_null(footer->uuid))
     314                 :            :                 return "invalid (NULL) uuid";
     315                 :            : 
     316                 :          0 :         return NULL;
     317                 :            : }
     318                 :            : 
     319                 :            : static char *
     320                 :          0 : vhd_util_check_validate_header(int fd, vhd_header_t *header)
     321                 :            : {
     322                 :            :         off64_t eof;
     323                 :            :         int i, cnt, size;
     324                 :            :         uint32_t checksum;
     325                 :            : 
     326                 :          0 :         size = sizeof(header->cookie);
     327         [ #  # ]:          0 :         if (memcmp(header->cookie, DD_COOKIE, size))
     328                 :            :                 return "invalid cookie";
     329                 :            : 
     330                 :          0 :         checksum = vhd_checksum_header(header);
     331         [ #  # ]:          0 :         if (checksum != header->checksum)
     332                 :            :                 return "invalid checksum";
     333                 :            : 
     334         [ #  # ]:          0 :         if (header->hdr_ver != 0x00010000)
     335                 :            :                 return "invalid header version";
     336                 :            : 
     337         [ #  # ]:          0 :         if (header->data_offset != ~(0ULL))
     338                 :            :                 return "invalid data offset";
     339                 :            : 
     340                 :          0 :         eof = lseek64(fd, 0, SEEK_END);
     341         [ #  # ]:          0 :         if (eof == (off64_t)-1)
     342                 :            :                 return "error finding eof";
     343                 :            : 
     344 [ #  # ][ #  # ]:          0 :         if (header->table_offset <= 0  ||
     345         [ #  # ]:          0 :             header->table_offset % 512 ||
     346                 :          0 :             (header->table_offset +
     347                 :          0 :              (header->max_bat_size * sizeof(uint32_t)) >
     348                 :          0 :              eof - sizeof(vhd_footer_t)))
     349                 :            :                 return "invalid table offset";
     350                 :            : 
     351         [ #  # ]:          0 :         for (cnt = 0, i = 0; i < sizeof(header->block_size) * 8; i++)
     352         [ #  # ]:          0 :                 if ((header->block_size >> i) & 1)
     353                 :          0 :                         cnt++;
     354                 :            : 
     355         [ #  # ]:          0 :         if (cnt != 1)
     356                 :            :                 return "invalid block size";
     357                 :            : 
     358         [ #  # ]:          0 :         if (header->res1)
     359                 :            :                 return "invalid reserved bits";
     360                 :            : 
     361         [ #  # ]:          0 :         if (vhd_util_check_zeros(header->res2, sizeof(header->res2)))
     362                 :            :                 return "invalid reserved bits";
     363                 :            : 
     364                 :          0 :         return NULL;
     365                 :            : }
     366                 :            : 
     367                 :            : static char *
     368                 :          0 : vhd_util_check_validate_differencing_header(struct vhd_util_check_ctx *ctx,
     369                 :            :                                             vhd_context_t *vhd)
     370                 :            : {
     371                 :            :         vhd_header_t *header;
     372                 :            : 
     373                 :          0 :         header = &vhd->header;
     374                 :            : 
     375         [ #  # ]:          0 :         if (vhd->footer.type == HD_TYPE_DIFF) {
     376                 :            :                 char *parent;
     377                 :            : 
     378         [ #  # ]:          0 :                 if (!ctx->opts.ignore_timestamps) {
     379                 :          0 :                         uint32_t now = vhd_time(time(NULL));
     380         [ #  # ]:          0 :                         if (header->prt_ts > now + TIMESTAMP_MAX_SLACK)
     381                 :          0 :                                 return "parent creation time in future";
     382                 :            :                 }
     383                 :            : 
     384         [ #  # ]:          0 :                 if (vhd_header_decode_parent(vhd, header, &parent))
     385                 :            :                         return "invalid parent name";
     386                 :            : 
     387                 :          0 :                 free(parent);
     388                 :            :         } else {
     389         [ #  # ]:          0 :                 if (vhd_util_check_zeros(header->prt_name,
     390                 :            :                                          sizeof(header->prt_name)))
     391                 :            :                         return "invalid non-null parent name";
     392                 :            : 
     393         [ #  # ]:          0 :                 if (vhd_util_check_zeros(header->loc, sizeof(header->loc)))
     394                 :            :                         return "invalid non-null parent locators";
     395                 :            : 
     396         [ #  # ]:          0 :                 if (!uuid_is_null(header->prt_uuid))
     397                 :            :                         return "invalid non-null parent uuid";
     398                 :            : 
     399         [ #  # ]:          0 :                 if (header->prt_ts)
     400                 :            :                         return "invalid non-zero parent timestamp";
     401                 :            :         }
     402                 :            : 
     403                 :            :         return NULL;
     404                 :            : }
     405                 :            : 
     406                 :            : static char *
     407                 :          0 : vhd_util_check_validate_batmap(vhd_context_t *vhd, vhd_batmap_t *batmap)
     408                 :            : {
     409                 :            :         int size;
     410                 :            :         off64_t eof;
     411                 :            :         uint32_t checksum;
     412                 :            : 
     413                 :          0 :         size = sizeof(batmap->header.cookie);
     414         [ #  # ]:          0 :         if (memcmp(batmap->header.cookie, VHD_BATMAP_COOKIE, size))
     415                 :            :                 return "invalid cookie";
     416                 :            : 
     417         [ #  # ]:          0 :         if (batmap->header.batmap_version > VHD_BATMAP_CURRENT_VERSION)
     418                 :            :                 return "unsupported batmap version";
     419                 :            : 
     420                 :          0 :         checksum = vhd_checksum_batmap(vhd, batmap);
     421         [ #  # ]:          0 :         if (checksum != batmap->header.checksum)
     422                 :            :                 return "invalid checksum";
     423                 :            : 
     424         [ #  # ]:          0 :         if (!batmap->header.batmap_size)
     425                 :            :                 return "invalid size zero";
     426                 :            : 
     427         [ #  # ]:          0 :         if (batmap->header.batmap_size << (VHD_SECTOR_SHIFT + 3) <
     428                 :          0 :                         vhd->header.max_bat_size)
     429                 :            :                 return "batmap-BAT size mismatch";
     430                 :            : 
     431                 :          0 :         eof = lseek64(vhd->fd, 0, SEEK_END);
     432         [ #  # ]:          0 :         if (eof == (off64_t)-1)
     433                 :            :                 return "error finding eof";
     434                 :            : 
     435 [ #  # ][ #  # ]:          0 :         if (!batmap->header.batmap_offset ||
     436                 :          0 :             batmap->header.batmap_offset % 512)
     437                 :            :                 return "invalid batmap offset";
     438                 :            : 
     439         [ #  # ]:          0 :         if ((batmap->header.batmap_offset +
     440                 :          0 :              vhd_sectors_to_bytes(batmap->header.batmap_size)) >
     441                 :          0 :             eof - sizeof(vhd_footer_t))
     442                 :            :                 return "invalid batmap size";
     443                 :            : 
     444                 :          0 :         return NULL;
     445                 :            : }
     446                 :            : 
     447                 :            : static char *
     448                 :          0 : vhd_util_check_validate_parent_locator(vhd_context_t *vhd,
     449                 :          0 :                                        vhd_parent_locator_t *loc)
     450                 :            : {
     451                 :            :         off64_t eof;
     452                 :            : 
     453         [ #  # ]:          0 :         if (vhd_validate_platform_code(loc->code))
     454                 :            :                 return "invalid platform code";
     455                 :            : 
     456         [ #  # ]:          0 :         if (loc->code == PLAT_CODE_NONE) {
     457         [ #  # ]:          0 :                 if (vhd_util_check_zeros(loc, sizeof(*loc)))
     458                 :            :                         return "non-zero locator";
     459                 :            : 
     460                 :          0 :                 return NULL;
     461                 :            :         }
     462                 :            : 
     463         [ #  # ]:          0 :         if (!loc->data_offset)
     464                 :            :                 return "invalid data offset";
     465                 :            : 
     466         [ #  # ]:          0 :         if (!loc->data_space)
     467                 :            :                 return "invalid data space";
     468                 :            : 
     469         [ #  # ]:          0 :         if (!loc->data_len)
     470                 :            :                 return "invalid data length";
     471                 :            : 
     472                 :          0 :         eof = lseek64(vhd->fd, 0, SEEK_END);
     473         [ #  # ]:          0 :         if (eof == (off64_t)-1)
     474                 :            :                 return "error finding eof";
     475                 :            : 
     476         [ #  # ]:          0 :         if (loc->data_offset + vhd_parent_locator_size(loc) >
     477                 :          0 :             eof - sizeof(vhd_footer_t))
     478                 :            :                 return "invalid size";
     479                 :            : 
     480         [ #  # ]:          0 :         if (loc->res)
     481                 :            :                 return "invalid reserved bits";
     482                 :            : 
     483                 :          0 :         return NULL;
     484                 :            : }
     485                 :            : 
     486                 :            : static char *
     487                 :          0 : vhd_util_check_validate_parent(struct vhd_util_check_ctx *ctx,
     488                 :            :                                vhd_context_t *vhd, const char *ppath)
     489                 :            : {
     490                 :            :         char *msg;
     491                 :            :         vhd_context_t parent;
     492                 :            : 
     493                 :          0 :         msg = NULL;
     494                 :            : 
     495         [ #  # ]:          0 :         if (vhd_parent_raw(vhd))
     496                 :          0 :                 return msg;
     497                 :            : 
     498         [ #  # ]:          0 :         if (ctx->opts.ignore_parent_uuid)
     499                 :            :                 return msg;
     500                 :            : 
     501         [ #  # ]:          0 :         if (vhd_open(&parent, ppath,
     502                 :            :                                 VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED))
     503                 :            :                 return "error opening parent";
     504                 :            : 
     505         [ #  # ]:          0 :         if (uuid_compare(vhd->header.prt_uuid, parent.footer.uuid)) {
     506                 :          0 :                 msg = "invalid parent uuid";
     507                 :          0 :                 goto out;
     508                 :            :         }
     509                 :            : 
     510                 :            : out:
     511                 :          0 :         vhd_close(&parent);
     512                 :            :         return msg;
     513                 :            : }
     514                 :            : 
     515                 :            : static int
     516                 :          0 : vhd_util_check_footer(struct vhd_util_check_ctx *ctx,
     517                 :            :                       int fd, vhd_footer_t *footer)
     518                 :            : {
     519                 :            :         int err;
     520                 :            :         size_t size;
     521                 :            :         char *msg;
     522                 :            :         void *buf;
     523                 :            :         off64_t eof, off;
     524                 :            :         vhd_footer_t primary, backup;
     525                 :            : 
     526                 :            :         memset(&primary, 0, sizeof(primary));
     527                 :            :         memset(&backup, 0, sizeof(backup));
     528                 :            : 
     529                 :          0 :         err = posix_memalign(&buf, VHD_SECTOR_SIZE, sizeof(primary));
     530         [ #  # ]:          0 :         if (err) {
     531                 :            :                 printf("error allocating buffer: %d\n", err);
     532                 :          0 :                 return -err;
     533                 :            :         }
     534                 :            : 
     535                 :          0 :         memset(buf, 0, sizeof(primary));
     536                 :            : 
     537                 :          0 :         eof = lseek64(fd, 0, SEEK_END);
     538         [ #  # ]:          0 :         if (eof == (off64_t)-1) {
     539                 :          0 :                 err = -errno;
     540                 :            :                 printf("error calculating end of file: %d\n", err);
     541                 :            :                 goto out;
     542                 :            :         }
     543                 :            : 
     544         [ #  # ]:          0 :         size = ((eof % 512) ? 511 : 512);
     545                 :          0 :         eof  = lseek64(fd, eof - size, SEEK_SET);
     546         [ #  # ]:          0 :         if (eof == (off64_t)-1) {
     547                 :          0 :                 err = -errno;
     548                 :            :                 printf("error calculating end of file: %d\n", err);
     549                 :            :                 goto out;
     550                 :            :         }
     551                 :            : 
     552                 :          0 :         err = read(fd, buf, 512);
     553         [ #  # ]:          0 :         if (err != size) {
     554         [ #  # ]:          0 :                 err = (errno ? -errno : -EIO);
     555                 :            :                 printf("error reading primary footer: %d\n", err);
     556                 :            :                 goto out;
     557                 :            :         }
     558                 :            : 
     559                 :          0 :         memcpy(&primary, buf, sizeof(primary));
     560                 :          0 :         vhd_footer_in(&primary);
     561                 :            : 
     562                 :          0 :         msg = vhd_util_check_validate_footer(ctx, &primary);
     563         [ #  # ]:          0 :         if (msg) {
     564                 :          0 :                 ctx->primary_footer_missing = 1;
     565                 :            : 
     566         [ #  # ]:          0 :                 if (ctx->opts.ignore_footer)
     567                 :            :                         goto check_backup;
     568                 :            : 
     569                 :          0 :                 err = -EINVAL;
     570                 :            :                 printf("primary footer invalid: %s\n", msg);
     571                 :            :                 goto out;
     572                 :            :         }
     573                 :            : 
     574         [ #  # ]:          0 :         if (primary.type == HD_TYPE_FIXED) {
     575                 :            :                 err = 0;
     576                 :            :                 goto out;
     577                 :            :         }
     578                 :            : 
     579                 :            : check_backup:
     580                 :          0 :         off = lseek64(fd, 0, SEEK_SET);
     581         [ #  # ]:          0 :         if (off == (off64_t)-1) {
     582                 :          0 :                 err = -errno;
     583                 :            :                 printf("error seeking to backup footer: %d\n", err);
     584                 :            :                 goto out;
     585                 :            :         }
     586                 :            : 
     587                 :          0 :         size = 512;
     588                 :          0 :         memset(buf, 0, sizeof(primary));
     589                 :            : 
     590                 :          0 :         err = read(fd, buf, size);
     591         [ #  # ]:          0 :         if (err != size) {
     592         [ #  # ]:          0 :                 err = (errno ? -errno : -EIO);
     593                 :            :                 printf("error reading backup footer: %d\n", err);
     594                 :            :                 goto out;
     595                 :            :         }
     596                 :            : 
     597                 :          0 :         memcpy(&backup, buf, sizeof(backup));
     598                 :          0 :         vhd_footer_in(&backup);
     599                 :            : 
     600                 :          0 :         msg = vhd_util_check_validate_footer(ctx, &backup);
     601         [ #  # ]:          0 :         if (msg) {
     602                 :          0 :                 err = -EINVAL;
     603                 :            :                 printf("backup footer invalid: %s\n", msg);
     604                 :            :                 goto out;
     605                 :            :         }
     606                 :            : 
     607         [ #  # ]:          0 :         if (memcmp(&primary, &backup, sizeof(primary))) {
     608         [ #  # ]:          0 :                 if (ctx->opts.ignore_footer) {
     609                 :            :                         memcpy(&primary, &backup, sizeof(primary));
     610                 :            :                         goto ok;
     611                 :            :                 }
     612                 :            : 
     613 [ #  # ][ #  # ]:          0 :                 if (backup.hidden &&
     614         [ #  # ]:          0 :                     !strncmp(backup.crtr_app, "tap", 3) &&
     615                 :          0 :                     (backup.crtr_ver == VHD_VERSION(0, 1) ||
     616                 :            :                      backup.crtr_ver == VHD_VERSION(1, 1))) {
     617                 :            :                         int cmp;
     618                 :          0 :                         char tmp = backup.hidden;
     619                 :          0 :                         backup.hidden = 0;
     620                 :          0 :                         cmp = memcmp(&primary, &backup, sizeof(primary));
     621                 :          0 :                         backup.hidden = tmp;
     622         [ #  # ]:          0 :                         if (!cmp)
     623                 :            :                                 goto ok;
     624                 :            :                 }
     625                 :            : 
     626                 :          0 :                 err = -EINVAL;
     627                 :            :                 printf("primary and backup footers do not match\n");
     628                 :            :                 goto out;
     629                 :            :         }
     630                 :            : 
     631                 :            : ok:
     632                 :          0 :         err = 0;
     633                 :            :         memcpy(footer, &primary, sizeof(primary));
     634                 :            : 
     635                 :            : out:
     636                 :          0 :         free(buf);
     637                 :          0 :         return err;
     638                 :            : }
     639                 :            : 
     640                 :            : static int
     641                 :          0 : vhd_util_check_header(int fd, vhd_footer_t *footer)
     642                 :            : {
     643                 :            :         int err;
     644                 :            :         off64_t off;
     645                 :            :         char *msg;
     646                 :            :         void *buf;
     647                 :            :         vhd_header_t header;
     648                 :            : 
     649                 :          0 :         err = posix_memalign(&buf, VHD_SECTOR_SIZE, sizeof(header));
     650         [ #  # ]:          0 :         if (err) {
     651                 :            :                 printf("error allocating header: %d\n", err);
     652                 :          0 :                 return err;
     653                 :            :         }
     654                 :            : 
     655                 :          0 :         off = footer->data_offset;
     656                 :          0 :         off = lseek64(fd, off, SEEK_SET);
     657         [ #  # ]:          0 :         if (off == (off64_t)-1) {
     658                 :          0 :                 err = -errno;
     659                 :            :                 printf("error seeking to header: %d\n", err);
     660                 :            :                 goto out;
     661                 :            :         }
     662                 :            : 
     663                 :          0 :         err = read(fd, buf, sizeof(header));
     664         [ #  # ]:          0 :         if (err != sizeof(header)) {
     665         [ #  # ]:          0 :                 err = (errno ? -errno : -EIO);
     666                 :            :                 printf("error reading header: %d\n", err);
     667                 :            :                 goto out;
     668                 :            :         }
     669                 :            : 
     670                 :          0 :         memcpy(&header, buf, sizeof(header));
     671                 :          0 :         vhd_header_in(&header);
     672                 :            : 
     673                 :          0 :         msg = vhd_util_check_validate_header(fd, &header);
     674         [ #  # ]:          0 :         if (msg) {
     675                 :          0 :                 err = -EINVAL;
     676                 :            :                 printf("header is invalid: %s\n", msg);
     677                 :            :                 goto out;
     678                 :            :         }
     679                 :            : 
     680                 :            :         err = 0;
     681                 :            : 
     682                 :            : out:
     683                 :          0 :         free(buf);
     684                 :          0 :         return err;
     685                 :            : }
     686                 :            : 
     687                 :            : static int
     688                 :          0 : vhd_util_check_differencing_header(struct vhd_util_check_ctx *ctx,
     689                 :            :                                    vhd_context_t *vhd)
     690                 :            : {
     691                 :            :         char *msg;
     692                 :            : 
     693                 :          0 :         msg = vhd_util_check_validate_differencing_header(ctx, vhd);
     694         [ #  # ]:          0 :         if (msg) {
     695                 :            :                 printf("differencing header is invalid: %s\n", msg);
     696                 :          0 :                 return -EINVAL;
     697                 :            :         }
     698                 :            : 
     699                 :            :         return 0;
     700                 :            : }
     701                 :            : 
     702                 :            : static int
     703                 :          0 : vhd_util_check_bitmap(struct vhd_util_check_ctx *ctx,
     704                 :            :                       vhd_context_t *vhd, uint32_t block)
     705                 :            : {
     706                 :            :         int err, i;
     707                 :            :         uint64_t sector;
     708                 :            :         char *bitmap, *data;
     709                 :            : 
     710                 :          0 :         data   = NULL;
     711                 :          0 :         bitmap = NULL;
     712                 :          0 :         sector = (uint64_t)block * vhd->spb;
     713                 :            : 
     714                 :          0 :         err = vhd_read_bitmap(vhd, block, &bitmap);
     715         [ #  # ]:          0 :         if (err) {
     716                 :            :                 printf("error reading bitmap 0x%x\n", block);
     717                 :            :                 goto out;
     718                 :            :         }
     719                 :            : 
     720         [ #  # ]:          0 :         if (ctx->opts.check_data) {
     721                 :          0 :                 err = vhd_read_block(vhd, block, &data);
     722         [ #  # ]:          0 :                 if (err) {
     723                 :            :                         printf("error reading data block 0x%x\n", block);
     724                 :            :                         goto out;
     725                 :            :                 }
     726                 :            :         }
     727                 :            : 
     728         [ #  # ]:          0 :         for (i = 0; i < vhd->spb; i++) {
     729   [ #  #  #  # ]:          0 :                 if (ctx->opts.collect_stats &&
     730                 :          0 :                     vhd_bitmap_test(vhd, bitmap, i)) {
     731                 :          0 :                         ctx_cur_stats(ctx)->secs_written++;
     732                 :          0 :                         set_bit_u64(ctx_cur_stats(ctx)->bitmap, sector + i);
     733                 :            :                 }
     734                 :            : 
     735         [ #  # ]:          0 :                 if (ctx->opts.check_data) {
     736                 :          0 :                         char *buf = data + (i << VHD_SECTOR_SHIFT);
     737                 :          0 :                         int set   = vhd_util_check_zeros(buf, VHD_SECTOR_SIZE);
     738                 :          0 :                         int map   = vhd_bitmap_test(vhd, bitmap, i);
     739                 :            : 
     740         [ #  # ]:          0 :                         if (set && !map) {
     741                 :            :                                 printf("sector 0x%x of block 0x%x has data "
     742                 :            :                                        "where bitmap is clear\n", i, block);
     743                 :            :                                 err = -EINVAL;
     744                 :            :                         }
     745                 :            :                 }
     746                 :            :         }
     747                 :            : 
     748                 :            : out:
     749                 :          0 :         free(data);
     750                 :          0 :         free(bitmap);
     751                 :          0 :         return err;
     752                 :            : }
     753                 :            : 
     754                 :            : static int
     755                 :          0 : vhd_util_check_bat(struct vhd_util_check_ctx *ctx, vhd_context_t *vhd)
     756                 :            : {
     757                 :            :         off64_t eof, eoh;
     758                 :            :         uint64_t vhd_blks;
     759                 :            :         int i, j, err, block_size;
     760                 :            : 
     761         [ #  # ]:          0 :         if (ctx->opts.collect_stats) {
     762                 :          0 :                 err = vhd_util_check_stats_alloc_one(ctx, vhd);
     763         [ #  # ]:          0 :                 if (err)
     764                 :          0 :                         return err;
     765                 :            :         }
     766                 :            : 
     767                 :          0 :         err = vhd_seek(vhd, 0, SEEK_END);
     768         [ #  # ]:          0 :         if (err) {
     769                 :            :                 printf("error calculating eof: %d\n", err);
     770                 :            :                 return err;
     771                 :            :         }
     772                 :            : 
     773                 :          0 :         eof = vhd_position(vhd);
     774         [ #  # ]:          0 :         if (eof == (off64_t)-1) {
     775                 :          0 :                 printf("error calculating eof: %d\n", -errno);
     776                 :          0 :                 return -errno;
     777                 :            :         }
     778                 :            : 
     779                 :            :         /* adjust eof for vhds with short footers */
     780         [ #  # ]:          0 :         if (eof % 512) {
     781         [ #  # ]:          0 :                 if (eof % 512 != 511) {
     782                 :            :                         printf("invalid file size: 0x%"PRIx64"\n", eof);
     783                 :            :                         return -EINVAL;
     784                 :            :                 }
     785                 :            : 
     786                 :          0 :                 eof++;
     787                 :            :         }
     788                 :            : 
     789                 :          0 :         err = vhd_get_bat(vhd);
     790         [ #  # ]:          0 :         if (err) {
     791                 :            :                 printf("error reading bat: %d\n", err);
     792                 :            :                 return err;
     793                 :            :         }
     794                 :            : 
     795                 :          0 :         err = vhd_end_of_headers(vhd, &eoh);
     796         [ #  # ]:          0 :         if (err) {
     797                 :            :                 printf("error calculating end of metadata: %d\n", err);
     798                 :            :                 return err;
     799                 :            :         }
     800                 :            : 
     801                 :          0 :         eof  -= sizeof(vhd_footer_t);
     802                 :          0 :         eof >>= VHD_SECTOR_SHIFT;
     803                 :          0 :         eoh >>= VHD_SECTOR_SHIFT;
     804                 :          0 :         block_size = vhd->spb + vhd->bm_secs;
     805                 :            : 
     806                 :          0 :         vhd_blks = vhd->footer.curr_size >> VHD_BLOCK_SHIFT;
     807         [ #  # ]:          0 :         if (vhd_blks > vhd->header.max_bat_size) {
     808                 :          0 :                 printf("VHD size (%"PRIu64" blocks) exceeds BAT size (%u)\n",
     809                 :            :                        vhd_blks, vhd->header.max_bat_size);
     810                 :            :                 return -EINVAL;
     811                 :            :         }
     812                 :            : 
     813         [ #  # ]:          0 :         for (i = 0; i < vhd_blks; i++) {
     814                 :          0 :                 uint32_t off = vhd->bat.bat[i];
     815         [ #  # ]:          0 :                 if (off == DD_BLK_UNUSED)
     816                 :          0 :                         continue;
     817                 :            : 
     818         [ #  # ]:          0 :                 if (off < eoh) {
     819                 :            :                         printf("block %d (offset 0x%x) clobbers headers\n",
     820                 :            :                                i, off);
     821                 :            :                         return -EINVAL;
     822                 :            :                 }
     823                 :            : 
     824         [ #  # ]:          0 :                 if (off + block_size > eof) {
     825 [ #  # ][ #  # ]:          0 :                         if (!(ctx->primary_footer_missing &&
                 [ #  # ]
     826                 :          0 :                               ctx->opts.ignore_footer     &&
     827                 :          0 :                               off + block_size == eof + 1)) {
     828                 :            :                                 printf("block %d (offset 0x%x) clobbers "
     829                 :            :                                        "footer\n", i, off);
     830                 :            :                                 return -EINVAL;
     831                 :            :                         }
     832                 :            :                 }
     833                 :            : 
     834         [ #  # ]:          0 :                 if (ctx->opts.no_check_bat)
     835                 :          0 :                         continue;
     836                 :            : 
     837         [ #  # ]:          0 :                 for (j = 0; j < vhd_blks; j++) {
     838                 :          0 :                         uint32_t joff = vhd->bat.bat[j];
     839                 :            : 
     840         [ #  # ]:          0 :                         if (i == j)
     841                 :          0 :                                 continue;
     842                 :            : 
     843         [ #  # ]:          0 :                         if (joff == DD_BLK_UNUSED)
     844                 :          0 :                                 continue;
     845                 :            : 
     846         [ #  # ]:          0 :                         if (off == joff)
     847                 :          0 :                                 err = -EINVAL;
     848                 :            : 
     849 [ #  # ][ #  # ]:          0 :                         if (off > joff && off < joff + block_size)
     850                 :          0 :                                 err = -EINVAL;
     851                 :            : 
     852 [ #  # ][ #  # ]:          0 :                         if (off + block_size > joff &&
     853                 :          0 :                             off + block_size < joff + block_size)
     854                 :          0 :                                 err = -EINVAL;
     855                 :            : 
     856         [ #  # ]:          0 :                         if (err) {
     857                 :            :                                 printf("block %d (offset 0x%x) clobbers "
     858                 :            :                                        "block %d (offset 0x%x)\n",
     859                 :            :                                        i, off, j, joff);
     860                 :            :                                 return err;
     861                 :            :                         }
     862                 :            :                 }
     863                 :            : 
     864         [ #  # ]:          0 :                 if (ctx->opts.check_data || ctx->opts.collect_stats) {
     865         [ #  # ]:          0 :                         if (ctx->opts.collect_stats)
     866                 :          0 :                                 ctx_cur_stats(ctx)->secs_allocated += vhd->spb;
     867                 :            : 
     868                 :          0 :                         err = vhd_util_check_bitmap(ctx, vhd, i);
     869         [ #  # ]:          0 :                         if (err)
     870                 :            :                                 return err;
     871                 :            :                 }
     872                 :            :         }
     873                 :            : 
     874                 :            :         return 0;
     875                 :            : }
     876                 :            : 
     877                 :            : static int
     878                 :          0 : vhd_util_check_batmap(vhd_context_t *vhd)
     879                 :            : {
     880                 :            :         char *msg;
     881                 :            :         int i, err;
     882                 :            : 
     883                 :          0 :         err = vhd_get_bat(vhd);
     884         [ #  # ]:          0 :         if (err) {
     885                 :            :                 printf("error reading bat: %d\n", err);
     886                 :          0 :                 return err;
     887                 :            :         }
     888                 :            : 
     889                 :          0 :         err = vhd_get_batmap(vhd);
     890         [ #  # ]:          0 :         if (err) {
     891                 :            :                 printf("error reading batmap: %d\n", err);
     892                 :          0 :                 return err;
     893                 :            :         }
     894                 :            : 
     895                 :          0 :         msg = vhd_util_check_validate_batmap(vhd, &vhd->batmap);
     896         [ #  # ]:          0 :         if (msg) {
     897                 :            :                 printf("batmap is invalid: %s\n", msg);
     898                 :          0 :                 return -EINVAL;
     899                 :            :         }
     900                 :            : 
     901         [ #  # ]:          0 :         for (i = 0; i < vhd->footer.curr_size >> VHD_BLOCK_SHIFT; i++) {
     902         [ #  # ]:          0 :                 if (!vhd_batmap_test(vhd, &vhd->batmap, i))
     903                 :          0 :                         continue;
     904                 :            : 
     905         [ #  # ]:          0 :                 if (vhd->bat.bat[i] == DD_BLK_UNUSED) {
     906                 :            :                         printf("batmap shows unallocated block %d full\n", i);
     907                 :          0 :                         return -EINVAL;
     908                 :            :                 }
     909                 :            :         }
     910                 :            : 
     911                 :            :         return 0;
     912                 :            : }
     913                 :            : 
     914                 :            : static int
     915                 :          0 : vhd_util_check_parent_locators(struct vhd_util_check_ctx *ctx,
     916                 :            :                                vhd_context_t *vhd)
     917                 :            : {
     918                 :            :         int i, n, err;
     919                 :            :         vhd_parent_locator_t *loc;
     920                 :            :         char *msg, *file, *ppath, *location, *pname;
     921                 :            :         int mac, macx, w2ku, w2ru, wi2r, wi2k, found;
     922                 :            : 
     923                 :          0 :         mac      = 0;
     924                 :          0 :         macx     = 0;
     925                 :          0 :         w2ku     = 0;
     926                 :          0 :         w2ru     = 0;
     927                 :          0 :         wi2r     = 0;
     928                 :          0 :         wi2k     = 0;
     929                 :          0 :         found    = 0;
     930                 :          0 :         pname    = NULL;
     931                 :          0 :         ppath    = NULL;
     932                 :          0 :         location = NULL;
     933                 :            : 
     934                 :          0 :         err = vhd_header_decode_parent(vhd, &vhd->header, &pname);
     935         [ #  # ]:          0 :         if (err) {
     936                 :            :                 printf("error decoding parent name: %d\n", err);
     937                 :          0 :                 return err;
     938                 :            :         }
     939                 :            : 
     940                 :            :         n = sizeof(vhd->header.loc) / sizeof(vhd->header.loc[0]);
     941         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     942                 :          0 :                 ppath    = NULL;
     943                 :          0 :                 location = NULL;
     944                 :          0 :                 loc = vhd->header.loc + i;
     945                 :            : 
     946                 :          0 :                 msg = vhd_util_check_validate_parent_locator(vhd, loc);
     947         [ #  # ]:          0 :                 if (msg) {
     948                 :          0 :                         err = -EINVAL;
     949                 :            :                         printf("invalid parent locator %d: %s\n", i, msg);
     950                 :            :                         goto out;
     951                 :            :                 }
     952                 :            : 
     953         [ #  # ]:          0 :                 if (loc->code == PLAT_CODE_NONE)
     954                 :          0 :                         continue;
     955                 :            : 
     956   [ #  #  #  #  :          0 :                 switch (loc->code) {
                #  #  # ]
     957                 :            :                 case PLAT_CODE_MACX:
     958         [ #  # ]:          0 :                         if (macx++)
     959                 :            :                                 goto dup;
     960                 :            :                         break;
     961                 :            : 
     962                 :            :                 case PLAT_CODE_MAC:
     963         [ #  # ]:          0 :                         if (mac++)
     964                 :            :                                 goto dup;
     965                 :            :                         break;
     966                 :            : 
     967                 :            :                 case PLAT_CODE_W2KU:
     968         [ #  # ]:          0 :                         if (w2ku++)
     969                 :            :                                 goto dup;
     970                 :            :                         break;
     971                 :            : 
     972                 :            :                 case PLAT_CODE_W2RU:
     973         [ #  # ]:          0 :                         if (w2ru++)
     974                 :            :                                 goto dup;
     975                 :            :                         break;
     976                 :            : 
     977                 :            :                 case PLAT_CODE_WI2R:
     978         [ #  # ]:          0 :                         if (wi2r++)
     979                 :            :                                 goto dup;
     980                 :            :                         break;
     981                 :            : 
     982                 :            :                 case PLAT_CODE_WI2K:
     983         [ #  # ]:          0 :                         if (wi2k++)
     984                 :            :                                 goto dup;
     985                 :            :                         break;
     986                 :            : 
     987                 :            :                 default:
     988                 :          0 :                         err = -EINVAL;
     989                 :            :                         printf("invalid  platform code for locator %d\n", i);
     990                 :            :                         goto out;
     991                 :            :                 }
     992                 :            : 
     993         [ #  # ]:          0 :                 if (loc->code != PLAT_CODE_MACX &&
     994         [ #  # ]:          0 :                     loc->code != PLAT_CODE_W2RU &&
     995                 :            :                     loc->code != PLAT_CODE_W2KU)
     996                 :          0 :                         continue;
     997                 :            : 
     998                 :          0 :                 err = vhd_parent_locator_read(vhd, loc, &ppath);
     999         [ #  # ]:          0 :                 if (err) {
    1000                 :            :                         printf("error reading parent locator %d: %d\n", i, err);
    1001                 :            :                         goto out;
    1002                 :            :                 }
    1003                 :            : 
    1004                 :          0 :                 file = basename(ppath);
    1005         [ #  # ]:          0 :                 if (strcmp(pname, file)) {
    1006                 :          0 :                         err = -EINVAL;
    1007                 :          0 :                         printf("parent locator %d name (%s) does not match "
    1008                 :            :                                "header name (%s)\n", i, file, pname);
    1009                 :            :                         goto out;
    1010                 :            :                 }
    1011                 :            : 
    1012                 :          0 :                 err = vhd_find_parent(vhd, ppath, &location);
    1013         [ #  # ]:          0 :                 if (err) {
    1014                 :          0 :                         printf("error resolving %s: %d\n", ppath, err);
    1015                 :            :                         goto out;
    1016                 :            :                 }
    1017                 :            : 
    1018                 :          0 :                 err = access(location, R_OK);
    1019 [ #  # ][ #  # ]:          0 :                 if (err && loc->code == PLAT_CODE_MACX) {
    1020                 :          0 :                         err = -errno;
    1021                 :          0 :                         printf("parent locator %d points to missing file %s "
    1022                 :            :                                 "(resolved to %s)\n", i, ppath, location);
    1023                 :            :                         goto out;
    1024                 :            :                 }
    1025                 :            : 
    1026                 :          0 :                 msg = vhd_util_check_validate_parent(ctx, vhd, location);
    1027         [ #  # ]:          0 :                 if (msg) {
    1028                 :          0 :                         err = -EINVAL;
    1029                 :          0 :                         printf("invalid parent %s: %s\n", location, msg);
    1030                 :            :                         goto out;
    1031                 :            :                 }
    1032                 :            : 
    1033                 :          0 :                 found++;
    1034                 :          0 :                 free(ppath);
    1035                 :          0 :                 free(location);
    1036                 :          0 :                 ppath = NULL;
    1037                 :          0 :                 location = NULL;
    1038                 :            : 
    1039                 :          0 :                 continue;
    1040                 :            : 
    1041                 :            :         dup:
    1042                 :          0 :                 printf("duplicate platform code in locator %d: 0x%x\n",
    1043                 :            :                        i, loc->code);
    1044                 :            :                 err = -EINVAL;
    1045                 :            :                 goto out;
    1046                 :            :         }
    1047                 :            : 
    1048         [ #  # ]:          0 :         if (!found) {
    1049                 :          0 :                 err = -EINVAL;
    1050                 :          0 :                 printf("could not find parent %s\n", pname);
    1051                 :            :                 goto out;
    1052                 :            :         }
    1053                 :            : 
    1054                 :            :         err = 0;
    1055                 :            : 
    1056                 :            : out:
    1057                 :          0 :         free(pname);
    1058                 :          0 :         free(ppath);
    1059                 :          0 :         free(location);
    1060                 :          0 :         return err;
    1061                 :            : }
    1062                 :            : 
    1063                 :            : static void
    1064                 :          0 : vhd_util_dump_headers(const char *name)
    1065                 :            : {
    1066                 :          0 :         char *argv[] = { "read", "-p", "-n", (char *)name };
    1067                 :          0 :         int argc = sizeof(argv) / sizeof(argv[0]);
    1068                 :            : 
    1069                 :            :         printf("%s appears invalid; dumping metadata\n", name);
    1070                 :          0 :         vhd_util_read(argc, argv);
    1071                 :          0 : }
    1072                 :            : 
    1073                 :            : static int
    1074                 :          0 : vhd_util_check_vhd(struct vhd_util_check_ctx *ctx, const char *name)
    1075                 :            : {
    1076                 :            :         int fd, err;
    1077                 :            :         vhd_context_t vhd;
    1078                 :            :         struct stat stats;
    1079                 :            :         vhd_footer_t footer;
    1080                 :            : 
    1081                 :            :         memset(&vhd, 0, sizeof(vhd));
    1082                 :            :         memset(&footer, 0, sizeof(footer));
    1083                 :            : 
    1084                 :          0 :         err = stat(name, &stats);
    1085         [ #  # ]:          0 :         if (err == -1) {
    1086                 :          0 :                 printf("cannot stat %s: %d\n", name, errno);
    1087                 :          0 :                 return -errno;
    1088                 :            :         }
    1089                 :            : 
    1090         [ #  # ]:          0 :         if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) {
    1091                 :            :                 printf("%s is not a regular file or block device\n", name);
    1092                 :            :                 return -EINVAL;
    1093                 :            :         }
    1094                 :            : 
    1095                 :          0 :         fd = open_optional_odirect(name, O_RDONLY | O_DIRECT | O_LARGEFILE);
    1096         [ #  # ]:          0 :         if (fd == -1) {
    1097                 :            :                 printf("error opening %s\n", name);
    1098                 :          0 :                 return -errno;
    1099                 :            :         }
    1100                 :            : 
    1101                 :          0 :         err = vhd_util_check_footer(ctx, fd, &footer);
    1102         [ #  # ]:          0 :         if (err)
    1103                 :            :                 goto out;
    1104                 :            : 
    1105         [ #  # ]:          0 :         if (footer.type != HD_TYPE_DYNAMIC && footer.type != HD_TYPE_DIFF)
    1106                 :            :                 goto out;
    1107                 :            : 
    1108                 :          0 :         err = vhd_util_check_header(fd, &footer);
    1109         [ #  # ]:          0 :         if (err)
    1110                 :            :                 goto out;
    1111                 :            : 
    1112                 :          0 :         err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
    1113         [ #  # ]:          0 :         if (err)
    1114                 :            :                 goto out;
    1115                 :            : 
    1116                 :          0 :         err = vhd_util_check_differencing_header(ctx, &vhd);
    1117         [ #  # ]:          0 :         if (err)
    1118                 :            :                 goto out;
    1119                 :            : 
    1120                 :          0 :         err = vhd_util_check_bat(ctx, &vhd);
    1121         [ #  # ]:          0 :         if (err)
    1122                 :            :                 goto out;
    1123                 :            : 
    1124         [ #  # ]:          0 :         if (vhd_has_batmap(&vhd)) {
    1125                 :          0 :                 err = vhd_util_check_batmap(&vhd);
    1126         [ #  # ]:          0 :                 if (err)
    1127                 :            :                         goto out;
    1128                 :            :         }
    1129                 :            : 
    1130         [ #  # ]:          0 :         if (vhd.footer.type == HD_TYPE_DIFF) {
    1131                 :          0 :                 err = vhd_util_check_parent_locators(ctx, &vhd);
    1132         [ #  # ]:          0 :                 if (err)
    1133                 :            :                         goto out;
    1134                 :            :         }
    1135                 :            : 
    1136                 :          0 :         err = 0;
    1137                 :            : 
    1138         [ #  # ]:          0 :         if (!ctx->opts.collect_stats)
    1139                 :            :                 printf("%s is valid\n", name);
    1140                 :            : 
    1141                 :            : out:
    1142         [ #  # ]:          0 :         if (err)
    1143                 :          0 :                 vhd_util_dump_headers(name);
    1144         [ #  # ]:          0 :         if (fd != -1)
    1145                 :          0 :                 close(fd);
    1146                 :          0 :         vhd_close(&vhd);
    1147                 :            :         return err;
    1148                 :            : }
    1149                 :            : 
    1150                 :            : static int
    1151                 :          0 : vhd_util_check_parents(struct vhd_util_check_ctx *ctx, const char *name)
    1152                 :            : {
    1153                 :            :         int err;
    1154                 :            :         vhd_context_t vhd;
    1155                 :            :         char *cur, *parent;
    1156                 :            : 
    1157                 :          0 :         cur = (char *)name;
    1158                 :            : 
    1159                 :            :         for (;;) {
    1160                 :          0 :                 err = vhd_open(&vhd, cur, 
    1161                 :            :                                 VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
    1162         [ #  # ]:          0 :                 if (err)
    1163                 :            :                         goto out;
    1164                 :            : 
    1165   [ #  #  #  # ]:          0 :                 if (vhd.footer.type != HD_TYPE_DIFF || vhd_parent_raw(&vhd)) {
    1166                 :          0 :                         vhd_close(&vhd);
    1167                 :            :                         goto out;
    1168                 :            :                 }
    1169                 :            : 
    1170                 :          0 :                 err = vhd_parent_locator_get(&vhd, &parent);
    1171                 :          0 :                 vhd_close(&vhd);
    1172                 :            : 
    1173         [ #  # ]:          0 :                 if (err) {
    1174                 :            :                         printf("error getting parent: %d\n", err);
    1175                 :            :                         goto out;
    1176                 :            :                 }
    1177                 :            : 
    1178         [ #  # ]:          0 :                 if (cur != name)
    1179                 :          0 :                         free(cur);
    1180                 :          0 :                 cur = parent;
    1181                 :            : 
    1182                 :          0 :                 err = vhd_util_check_vhd(ctx, cur);
    1183         [ #  # ]:          0 :                 if (err)
    1184                 :            :                         goto out;
    1185                 :            :         }
    1186                 :            : 
    1187                 :            : out:
    1188         [ #  # ]:          0 :         if (err)
    1189                 :            :                 printf("error checking parents: %d\n", err);
    1190         [ #  # ]:          0 :         if (cur != name)
    1191                 :          0 :                 free(cur);
    1192                 :          0 :         return err;
    1193                 :            : }
    1194                 :            : 
    1195                 :            : int
    1196                 :          0 : vhd_util_check(int argc, char **argv)
    1197                 :            : {
    1198                 :            :         char *name;
    1199                 :            :         int c, err, parents;
    1200                 :            :         struct vhd_util_check_ctx ctx;
    1201                 :            : 
    1202         [ #  # ]:          0 :         if (!argc || !argv) {
    1203                 :            :                 err = -EINVAL;
    1204                 :            :                 goto usage;
    1205                 :            :         }
    1206                 :            : 
    1207                 :          0 :         name    = NULL;
    1208                 :          0 :         parents = 0;
    1209                 :            :         memset(&ctx, 0, sizeof(ctx));
    1210                 :            :         vhd_util_check_stats_init(&ctx);
    1211                 :            : 
    1212                 :          0 :         optind = 0;
    1213         [ #  # ]:          0 :         while ((c = getopt(argc, argv, "n:iItpbBsh")) != -1) {
    1214   [ #  #  #  #  :          0 :                 switch (c) {
          #  #  #  #  #  
                      # ]
    1215                 :            :                 case 'n':
    1216                 :          0 :                         name = optarg;
    1217                 :          0 :                         break;
    1218                 :            :                 case 'i':
    1219                 :          0 :                         ctx.opts.ignore_footer = 1;
    1220                 :          0 :                         break;
    1221                 :            :                 case 'I':
    1222                 :          0 :                         ctx.opts.ignore_parent_uuid = 1;
    1223                 :          0 :                         break;
    1224                 :            :                 case 't':
    1225                 :          0 :                         ctx.opts.ignore_timestamps = 1;
    1226                 :          0 :                         break;
    1227                 :            :                 case 'p':
    1228                 :            :                         parents = 1;
    1229                 :            :                         break;
    1230                 :            :                 case 'b':
    1231                 :          0 :                         ctx.opts.check_data = 1;
    1232                 :          0 :                         break;
    1233                 :            :                 case 'B':
    1234                 :          0 :                         ctx.opts.no_check_bat = 1;
    1235                 :          0 :                         break;
    1236                 :            :                 case 's':
    1237                 :          0 :                         ctx.opts.collect_stats = 1;
    1238                 :          0 :                         break;
    1239                 :            :                 case 'h':
    1240                 :            :                         err = 0;
    1241                 :            :                         goto usage;
    1242                 :            :                 default:
    1243                 :          0 :                         err = -EINVAL;
    1244                 :          0 :                         goto usage;
    1245                 :            :                 }
    1246                 :            :         }
    1247                 :            : 
    1248 [ #  # ][ #  # ]:          0 :         if (!name || optind != argc) {
    1249                 :            :                 err = -EINVAL;
    1250                 :            :                 goto usage;
    1251                 :            :         }
    1252                 :            : 
    1253 [ #  # ][ #  # ]:          0 :         if ((ctx.opts.collect_stats || ctx.opts.check_data) &&
    1254                 :          0 :                         ctx.opts.no_check_bat) {
    1255                 :            :                 err = -EINVAL;
    1256                 :            :                 goto usage;
    1257                 :            :         }
    1258                 :            : 
    1259                 :          0 :         err = vhd_util_check_vhd(&ctx, name);
    1260         [ #  # ]:          0 :         if (err)
    1261                 :            :                 goto out;
    1262                 :            : 
    1263         [ #  # ]:          0 :         if (parents)
    1264                 :          0 :                 err = vhd_util_check_parents(&ctx, name);
    1265                 :            : 
    1266         [ #  # ]:          0 :         if (ctx.opts.collect_stats)
    1267                 :          0 :                 vhd_util_check_stats_print(&ctx);
    1268                 :            : 
    1269                 :          0 :         vhd_util_check_stats_free(&ctx);
    1270                 :            : 
    1271                 :            : out:
    1272                 :          0 :         return err;
    1273                 :            : 
    1274                 :            : usage:
    1275                 :            :         printf("options: -n <file> [-i ignore missing primary footers] "
    1276                 :            :                "[-I ignore parent uuids] [-t ignore timestamps] "
    1277                 :            :                "[-B do not check BAT for overlapping (precludes -s, -b)] "
    1278                 :            :                "[-p check parents] [-b check bitmaps] [-s stats] [-h help]\n");
    1279                 :            :         return err;
    1280                 :            : }

Generated by: LCOV version 1.13