LCOV - code coverage report
Current view: top level - vhd - vhd-index.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 605 0
Test Date: 2026-06-26 00:00:00 Functions: 0.0 % 20 0
Branches: 0.0 % 267 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 <string.h>
      41                 :             : #include <limits.h>
      42                 :             : 
      43                 :             : #include "libvhd.h"
      44                 :             : #include "libvhd-index.h"
      45                 :             : #include "util.h"
      46                 :             : 
      47                 :             : static void
      48                 :           0 : usage(void)
      49                 :             : {
      50                 :           0 :         printf("usage: vhd-index <command>\n"
      51                 :             :                "commands:\n"
      52                 :             :                "\t   index: <-i index name> <-v vhd file>\n"
      53                 :             :                "\t summary: <-s index name> [-v vhd file [-b block]]\n");
      54                 :           0 :         exit(-EINVAL);
      55                 :             : }
      56                 :             : 
      57                 :             : typedef struct vhdi_name              vhdi_name_t;
      58                 :             : 
      59                 :             : struct vhdi_name {
      60                 :             :         char                         *vhd;
      61                 :             :         char                         *bat;
      62                 :             : 
      63                 :             :         char                         *base;
      64                 :             :         char                         *index;
      65                 :             :         char                         *files;
      66                 :             : };
      67                 :             : 
      68                 :             : static int
      69                 :           0 : vhd_index_get_name(const char *index, const char *vhd, vhdi_name_t *name)
      70                 :             : {
      71                 :           0 :         int err, len;
      72                 :             : 
      73         [ #  # ]:           0 :         memset(name, 0, sizeof(vhdi_name_t));
      74                 :             : 
      75                 :           0 :         len = strnlen(index, VHD_MAX_NAME_LEN);
      76         [ #  # ]:           0 :         if (len + 5 >= VHD_MAX_NAME_LEN - 1)
      77                 :             :                 return -ENAMETOOLONG;
      78                 :             : 
      79         [ #  # ]:           0 :         if (vhd) {
      80                 :           0 :                 len = strnlen(vhd, VHD_MAX_NAME_LEN);
      81         [ #  # ]:           0 :                 if (len >= VHD_MAX_NAME_LEN - 1)
      82                 :             :                         return -ENAMETOOLONG;
      83                 :             : 
      84                 :           0 :                 err = asprintf(&name->vhd, "%s", vhd);
      85         [ #  # ]:           0 :                 if (err == -1) {
      86                 :           0 :                         name->vhd = NULL;
      87                 :           0 :                         goto fail;
      88                 :             :                 }
      89                 :             : 
      90                 :           0 :                 err = asprintf(&name->bat, "%s.bat", vhd);
      91         [ #  # ]:           0 :                 if (err == -1) {
      92                 :           0 :                         name->bat = NULL;
      93                 :           0 :                         goto fail;
      94                 :             :                 }
      95                 :             :         }
      96                 :             : 
      97                 :           0 :         err = asprintf(&name->base, "%s", index);
      98         [ #  # ]:           0 :         if (err == -1) {
      99                 :           0 :                 name->base = NULL;
     100                 :           0 :                 goto fail;
     101                 :             :         }
     102                 :             : 
     103                 :           0 :         err = asprintf(&name->index, "%s.index", index);
     104         [ #  # ]:           0 :         if (err == -1) {
     105                 :           0 :                 name->index = NULL;
     106                 :           0 :                 goto fail;
     107                 :             :         }
     108                 :             : 
     109                 :           0 :         err = asprintf(&name->files, "%s.files", index);
     110         [ #  # ]:           0 :         if (err == -1) {
     111                 :           0 :                 name->files = NULL;
     112                 :           0 :                 goto fail;
     113                 :             :         }
     114                 :             : 
     115                 :             :         return 0;
     116                 :             : 
     117                 :           0 : fail:
     118                 :           0 :         free(name->vhd);
     119                 :           0 :         free(name->bat);
     120                 :           0 :         free(name->base);
     121                 :           0 :         free(name->index);
     122                 :           0 :         free(name->files);
     123                 :             : 
     124                 :           0 :         return -ENOMEM;
     125                 :             : }
     126                 :             : 
     127                 :             : static inline void
     128                 :           0 : vhd_index_free_name(vhdi_name_t *name)
     129                 :             : {
     130                 :           0 :         free(name->vhd);
     131                 :           0 :         free(name->bat);
     132                 :           0 :         free(name->base);
     133                 :           0 :         free(name->index);
     134                 :           0 :         free(name->files);
     135                 :           0 : }
     136                 :             : 
     137                 :             : static inline int
     138                 :           0 : vhd_index_add_file_table_entry(vhdi_name_t *name, const char *file,
     139                 :             :                                vhdi_file_table_t *files, vhdi_file_id_t *fid)
     140                 :             : {
     141                 :           0 :         int err;
     142                 :             : 
     143                 :           0 :         vhdi_file_table_free(files);
     144                 :             : 
     145                 :           0 :         err = vhdi_file_table_add(name->files, file, fid);
     146         [ #  # ]:           0 :         if (err)
     147                 :             :                 return err;
     148                 :             : 
     149                 :           0 :         return vhdi_file_table_load(name->files, files);
     150                 :             : }
     151                 :             : 
     152                 :             : static inline int
     153                 :           0 : vhd_index_get_file_id(vhdi_name_t *name, const char *file,
     154                 :             :                       vhdi_file_table_t *files, vhdi_file_id_t *fid)
     155                 :             : {
     156                 :           0 :         char *path, __path[PATH_MAX];
     157                 :           0 :         int i;
     158                 :             : 
     159                 :           0 :         path = realpath(file, __path);
     160         [ #  # ]:           0 :         if (!path)
     161                 :           0 :                 return -errno;
     162                 :             : 
     163         [ #  # ]:           0 :         for (i = 0; i < files->entries; i++)
     164         [ #  # ]:           0 :                 if (!strcmp(files->table[i].path, path)) {
     165                 :           0 :                         *fid = files->table[i].file_id;
     166                 :           0 :                         return 0;
     167                 :             :                 }
     168                 :             : 
     169                 :           0 :         return vhd_index_add_file_table_entry(name, file, files, fid);
     170                 :             : }
     171                 :             : 
     172                 :             : static inline int
     173                 :           0 : vhd_index_get_block(vhdi_context_t *vhdi, vhd_context_t *vhd,
     174                 :             :                     uint32_t block, vhdi_block_t *vhdi_block)
     175                 :             : {
     176                 :           0 :         int i;
     177                 :             : 
     178         [ #  # ]:           0 :         if (block)
     179                 :           0 :                 return vhdi_read_block(vhdi, vhdi_block, block);
     180                 :             : 
     181                 :           0 :         vhdi_block->entries = vhd->spb;
     182                 :           0 :         vhdi_block->table   = calloc(vhd->spb, sizeof(vhdi_entry_t));
     183         [ #  # ]:           0 :         if (!vhdi_block->table)
     184                 :             :                 return -ENOMEM;
     185                 :             : 
     186         [ #  # ]:           0 :         for (i = 0; i < vhdi_block->entries; i++)
     187                 :           0 :                 vhdi_block->table[i].offset = DD_BLK_UNUSED;
     188                 :             : 
     189                 :             :         return 0;
     190                 :             : }
     191                 :             : 
     192                 :             : static int
     193                 :           0 : vhd_index_add_bat_entry(vhdi_name_t *name, vhdi_context_t *vhdi,
     194                 :             :                         vhdi_bat_t *bat, vhdi_file_table_t *files,
     195                 :             :                         vhd_context_t *vhd, uint32_t block, char *finished)
     196                 :             : {
     197                 :           0 :         char *map;
     198                 :           0 :         vhdi_file_id_t fid;
     199                 :           0 :         uint32_t i, count, off;
     200                 :           0 :         vhdi_block_t vhdi_block;
     201                 :           0 :         int err, update, append;
     202                 :             : 
     203                 :           0 :         fid    = 0;
     204                 :           0 :         count  = 0;
     205                 :           0 :         update = 0;
     206                 :           0 :         append = (bat->table[block] == 0);
     207                 :             : 
     208         [ #  # ]:           0 :         if (vhd->bat.bat[block] == DD_BLK_UNUSED)
     209                 :           0 :                 return 0;
     210                 :             : 
     211                 :           0 :         err = vhd_index_get_block(vhdi, vhd, bat->table[block], &vhdi_block);
     212         [ #  # ]:           0 :         if (err)
     213                 :             :                 return err;
     214                 :             : 
     215                 :           0 :         err = vhd_read_bitmap(vhd, block, &map);
     216         [ #  # ]:           0 :         if (err)
     217                 :           0 :                 goto out;
     218                 :             : 
     219                 :           0 :         err = vhd_index_get_file_id(name, vhd->file, files, &fid);
     220         [ #  # ]:           0 :         if (err)
     221                 :           0 :                 goto out;
     222                 :             : 
     223         [ #  # ]:           0 :         for (i = 0; i < vhd->spb; i++) {
     224         [ #  # ]:           0 :                 if (vhdi_block.table[i].file_id) {
     225                 :           0 :                         count++;
     226                 :           0 :                         continue;
     227                 :             :                 }
     228                 :             : 
     229         [ #  # ]:           0 :                 if (!vhd_bitmap_test(vhd, map, i))
     230                 :           0 :                         continue;
     231                 :             : 
     232                 :           0 :                 err = vhd_offset(vhd, (uint64_t)block * vhd->spb + i, &off);
     233         [ #  # ]:           0 :                 if (err)
     234                 :           0 :                         goto out;
     235                 :             : 
     236                 :           0 :                 vhdi_block.table[i].file_id = fid;
     237                 :           0 :                 vhdi_block.table[i].offset  = off;
     238                 :           0 :                 count++;
     239                 :           0 :                 update++;
     240                 :             :         }
     241                 :             : 
     242         [ #  # ]:           0 :         if (update) {
     243         [ #  # ]:           0 :                 if (append) {
     244                 :           0 :                         uint32_t location;
     245                 :             : 
     246                 :           0 :                         err = vhdi_append_block(vhdi, &vhdi_block, &location);
     247         [ #  # ]:           0 :                         if (err)
     248                 :           0 :                                 goto out;
     249                 :             : 
     250                 :           0 :                         bat->table[block] = location;
     251                 :             :                 } else {
     252                 :           0 :                         err = vhdi_write_block(vhdi, &vhdi_block,
     253                 :           0 :                                                bat->table[block]);
     254         [ #  # ]:           0 :                         if (err)
     255                 :           0 :                                 goto out;
     256                 :             :                 }
     257                 :             :         }
     258                 :             : 
     259         [ #  # ]:           0 :         if (count == vhd->spb)
     260                 :           0 :                 *finished = 1;
     261                 :             : 
     262                 :             :         err = 0;
     263                 :             : 
     264                 :           0 : out:
     265                 :           0 :         free(vhdi_block.table);
     266                 :           0 :         free(map);
     267                 :             : 
     268                 :           0 :         return err;
     269                 :             : }
     270                 :             : 
     271                 :             : static int
     272                 :           0 : vhd_index_clone_bat_entry(vhdi_name_t *name, vhdi_context_t *vhdi,
     273                 :             :                           vhdi_bat_t *bat, vhdi_file_table_t *files,
     274                 :             :                           vhd_context_t *vhd, uint32_t block)
     275                 :             : {
     276                 :           0 :         char *map;
     277                 :           0 :         int err, update;
     278                 :           0 :         uint32_t i, off;
     279                 :           0 :         vhdi_file_id_t fid;
     280                 :           0 :         vhdi_block_t vhdi_block;
     281                 :             : 
     282                 :           0 :         fid    = 0;
     283                 :           0 :         update = 0;
     284                 :             : 
     285         [ #  # ]:           0 :         if (vhd->bat.bat[block] == DD_BLK_UNUSED)
     286                 :           0 :                 return 0;
     287                 :             : 
     288                 :           0 :         err = vhd_index_get_block(vhdi, vhd, bat->table[block], &vhdi_block);
     289         [ #  # ]:           0 :         if (err)
     290                 :             :                 return err;
     291                 :             : 
     292                 :           0 :         err = vhd_read_bitmap(vhd, block, &map);
     293         [ #  # ]:           0 :         if (err)
     294                 :           0 :                 goto out;
     295                 :             : 
     296                 :           0 :         err = vhd_index_get_file_id(name, vhd->file, files, &fid);
     297         [ #  # ]:           0 :         if (err)
     298                 :           0 :                 goto out;
     299                 :             : 
     300         [ #  # ]:           0 :         for (i = 0; i < vhd->spb; i++) {
     301         [ #  # ]:           0 :                 if (!vhd_bitmap_test(vhd, map, i))
     302                 :           0 :                         continue;
     303                 :             : 
     304                 :           0 :                 err = vhd_offset(vhd, (uint64_t)block * vhd->spb + i, &off);
     305         [ #  # ]:           0 :                 if (err)
     306                 :           0 :                         goto out;
     307                 :             : 
     308                 :           0 :                 vhdi_block.table[i].file_id = fid;
     309                 :           0 :                 vhdi_block.table[i].offset  = off;
     310                 :           0 :                 update++;
     311                 :             :         }
     312                 :             : 
     313         [ #  # ]:           0 :         if (update) {
     314                 :           0 :                 uint32_t location;
     315                 :             : 
     316                 :           0 :                 err = vhdi_append_block(vhdi, &vhdi_block, &location);
     317         [ #  # ]:           0 :                 if (err)
     318                 :           0 :                         goto out;
     319                 :             : 
     320                 :           0 :                 bat->table[block] = location;
     321                 :             :         }
     322                 :             : 
     323                 :             :         err = 0;
     324                 :             : 
     325                 :           0 : out:
     326                 :           0 :         free(vhdi_block.table);
     327                 :           0 :         free(map);
     328                 :             : 
     329                 :           0 :         return err;
     330                 :             : }
     331                 :             : 
     332                 :             : static int
     333                 :           0 : vhd_index_update_bat_entry(vhdi_name_t *name, vhdi_context_t *vhdi,
     334                 :             :                            vhdi_bat_t *bat, vhdi_file_table_t *files,
     335                 :             :                            vhd_context_t *vhd, uint32_t block)
     336                 :             : {
     337                 :           0 :         char *map;
     338                 :           0 :         int err, update;
     339                 :           0 :         uint32_t i, off;
     340                 :           0 :         vhdi_file_id_t fid;
     341                 :           0 :         vhdi_block_t vhdi_block;
     342                 :             : 
     343                 :           0 :         fid    = 0;
     344                 :           0 :         update = 0;
     345                 :             : 
     346         [ #  # ]:           0 :         if (vhd->bat.bat[block] == DD_BLK_UNUSED)
     347                 :           0 :                 return 0;
     348                 :             : 
     349                 :           0 :         err = vhd_index_get_block(vhdi, vhd, bat->table[block], &vhdi_block);
     350         [ #  # ]:           0 :         if (err)
     351                 :             :                 return err;
     352                 :             : 
     353                 :           0 :         err = vhd_read_bitmap(vhd, block, &map);
     354         [ #  # ]:           0 :         if (err)
     355                 :           0 :                 goto out;
     356                 :             : 
     357                 :           0 :         err = vhd_index_get_file_id(name, vhd->file, files, &fid);
     358         [ #  # ]:           0 :         if (err)
     359                 :           0 :                 goto out;
     360                 :             : 
     361         [ #  # ]:           0 :         for (i = 0; i < vhd->spb; i++) {
     362         [ #  # ]:           0 :                 if (!vhd_bitmap_test(vhd, map, i))
     363                 :           0 :                         continue;
     364                 :             : 
     365                 :           0 :                 err = vhd_offset(vhd, (uint64_t)block * vhd->spb + i, &off);
     366         [ #  # ]:           0 :                 if (err)
     367                 :           0 :                         goto out;
     368                 :             : 
     369         [ #  # ]:           0 :                 if (vhdi_block.table[i].file_id == fid &&
     370         [ #  # ]:           0 :                     vhdi_block.table[i].offset  == off)
     371                 :           0 :                         continue;
     372                 :             : 
     373                 :           0 :                 vhdi_block.table[i].file_id = fid;
     374                 :           0 :                 vhdi_block.table[i].offset  = off;
     375                 :           0 :                 update++;
     376                 :             :         }
     377                 :             : 
     378         [ #  # ]:           0 :         if (update) {
     379                 :           0 :                 uint32_t location;
     380                 :             : 
     381                 :           0 :                 err = vhdi_append_block(vhdi, &vhdi_block, &location);
     382         [ #  # ]:           0 :                 if (err)
     383                 :           0 :                         goto out;
     384                 :             : 
     385                 :           0 :                 bat->table[block] = location;
     386                 :             :         }
     387                 :             : 
     388                 :             :         err = 0;
     389                 :             : 
     390                 :           0 : out:
     391                 :           0 :         free(vhdi_block.table);
     392                 :           0 :         free(map);
     393                 :             : 
     394                 :           0 :         return err;
     395                 :             : }
     396                 :             : 
     397                 :             : static int
     398                 :           0 : vhd_index_add_bat(vhdi_name_t *name,
     399                 :             :                   uint64_t vhd_blocks, uint32_t vhd_block_size)
     400                 :             : {
     401                 :           0 :         int err;
     402                 :           0 :         vhdi_bat_t bat;
     403                 :           0 :         vhd_context_t vhd;
     404                 :           0 :         vhdi_context_t vhdi;
     405                 :           0 :         vhdi_file_table_t files;
     406                 :           0 :         char *vhd_file, *finished;
     407                 :           0 :         uint32_t block, remaining;
     408                 :             : 
     409                 :           0 :         memset(&bat, 0, sizeof(vhdi_bat_t));
     410                 :           0 :         memset(&files, 0, sizeof(vhdi_file_table_t));
     411                 :             : 
     412                 :           0 :         vhd_file           = NULL;
     413                 :           0 :         finished           = NULL;
     414                 :           0 :         bat.vhd_blocks     = vhd_blocks;
     415                 :           0 :         bat.vhd_block_size = vhd_block_size;
     416                 :             : 
     417                 :           0 :         safe_strncpy(bat.vhd_path, name->vhd, sizeof(bat.vhd_path));
     418                 :           0 :         safe_strncpy(bat.index_path, name->index, sizeof(bat.index_path));
     419                 :           0 :         safe_strncpy(bat.file_table_path, name->files, sizeof(bat.file_table_path));
     420                 :             : 
     421                 :           0 :         err = vhdi_open(&vhdi, name->index, O_RDWR);
     422         [ #  # ]:           0 :         if (err)
     423                 :           0 :                 return err;
     424                 :             : 
     425                 :           0 :         err = vhdi_file_table_load(name->files, &files);
     426         [ #  # ]:           0 :         if (err) {
     427                 :           0 :                 vhdi_close(&vhdi);
     428                 :           0 :                 return err;
     429                 :             :         }
     430                 :             : 
     431                 :           0 :         err = vhdi_bat_create(name->bat, name->vhd, name->index, name->files);
     432         [ #  # ]:           0 :         if (err)
     433                 :           0 :                 goto out;
     434                 :             : 
     435                 :           0 :         bat.table = calloc(vhd_blocks, sizeof(uint32_t));
     436         [ #  # ]:           0 :         if (!bat.table) {
     437                 :           0 :                 err = -ENOMEM;
     438                 :           0 :                 goto out;
     439                 :             :         }
     440                 :             : 
     441                 :           0 :         vhd_file = strdup(name->vhd);
     442         [ #  # ]:           0 :         if (!vhd_file)
     443                 :           0 :                 goto out;
     444                 :             : 
     445                 :           0 :         remaining = vhd_blocks;
     446                 :           0 :         finished  = calloc(remaining, sizeof(char));
     447         [ #  # ]:           0 :         if (!finished) {
     448                 :           0 :                 err = -ENOMEM;
     449                 :           0 :                 goto out;
     450                 :             :         }
     451                 :             : 
     452                 :           0 :         for (;;) {
     453                 :           0 :                 err = vhd_open(&vhd, vhd_file, VHD_OPEN_RDONLY);
     454         [ #  # ]:           0 :                 if (err)
     455                 :           0 :                         goto out;
     456                 :             : 
     457                 :           0 :                 err = vhd_get_bat(&vhd);
     458         [ #  # ]:           0 :                 if (err)
     459                 :           0 :                         goto out_vhd;
     460                 :             : 
     461         [ #  # ]:           0 :                 for (block = 0; block < vhd.bat.entries; block++) {
     462         [ #  # ]:           0 :                         if (finished[block])
     463                 :           0 :                                 continue;
     464                 :             : 
     465                 :           0 :                         err = vhd_index_add_bat_entry(name, &vhdi, &bat,
     466                 :             :                                                       &files, &vhd, block,
     467                 :             :                                                       &finished[block]);
     468         [ #  # ]:           0 :                         if (err)
     469                 :           0 :                                 goto out_bat;
     470                 :             : 
     471         [ #  # ]:           0 :                         if (finished[block])
     472                 :           0 :                                 remaining--;
     473                 :             :                 }
     474                 :             : 
     475                 :           0 :                 free(vhd_file);
     476                 :           0 :                 vhd_file = NULL;
     477                 :             : 
     478   [ #  #  #  # ]:           0 :                 if (!remaining || vhd.footer.type != HD_TYPE_DIFF) {
     479                 :           0 :                         vhd_put_bat(&vhd);
     480                 :           0 :                         vhd_close(&vhd);
     481                 :           0 :                         break;
     482                 :             :                 }
     483                 :             : 
     484                 :           0 :                 err = vhd_parent_locator_get(&vhd, &vhd_file);
     485                 :             :                 if (err)
     486                 :             :                         goto out_bat;
     487                 :             : 
     488                 :           0 :         out_bat:
     489                 :           0 :                 vhd_put_bat(&vhd);
     490                 :           0 :         out_vhd:
     491                 :           0 :                 vhd_close(&vhd);
     492         [ #  # ]:           0 :                 if (err)
     493                 :           0 :                         goto out;
     494                 :             :         } 
     495                 :             : 
     496                 :           0 :         err = vhdi_bat_write(name->bat, &bat);
     497         [ #  # ]:           0 :         if (err)
     498                 :           0 :                 goto out;
     499                 :             : 
     500                 :             :         err = 0;
     501                 :             : 
     502                 :           0 : out:
     503         [ #  # ]:           0 :         if (err)
     504                 :           0 :                 unlink(name->bat);
     505                 :             : 
     506                 :           0 :         vhdi_file_table_free(&files);
     507                 :           0 :         vhdi_close(&vhdi);
     508                 :           0 :         free(bat.table);
     509                 :           0 :         free(finished);
     510                 :           0 :         free(vhd_file);
     511                 :             : 
     512                 :           0 :         return err;
     513                 :             : }
     514                 :             : 
     515                 :             : static int
     516                 :           0 : vhd_index_clone_bat(vhdi_name_t *name, const char *parent)
     517                 :             : {
     518                 :           0 :         int err;
     519                 :           0 :         char *pbat = NULL;
     520                 :           0 :         uint32_t block;
     521                 :           0 :         vhdi_bat_t bat;
     522                 :           0 :         vhd_context_t vhd;
     523                 :           0 :         vhdi_context_t vhdi;
     524                 :           0 :         vhdi_file_table_t files;
     525                 :             : 
     526                 :           0 :         memset(&bat, 0, sizeof(vhdi_bat_t));
     527                 :           0 :         memset(&files, 0, sizeof(vhdi_file_table_t));
     528                 :             : 
     529                 :           0 :         err = asprintf(&pbat, "%s.bat", parent);
     530         [ #  # ]:           0 :         if (err == -1) {
     531                 :           0 :                 free(pbat);
     532                 :           0 :                 return -ENOMEM;
     533                 :             :         }
     534                 :             : 
     535                 :           0 :         err = access(pbat, R_OK);
     536         [ #  # ]:           0 :         if (err == -1) {
     537                 :           0 :                 free(pbat);
     538                 :           0 :                 return -errno;
     539                 :             :         }
     540                 :             : 
     541                 :           0 :         err = vhdi_open(&vhdi, name->index, O_RDWR);
     542         [ #  # ]:           0 :         if (err)
     543                 :           0 :                 goto out;
     544                 :             : 
     545                 :           0 :         err = vhdi_bat_load(pbat, &bat);
     546         [ #  # ]:           0 :         if (err)
     547                 :           0 :                 goto out_vhdi;
     548                 :             : 
     549                 :           0 :         err = vhdi_file_table_load(name->files, &files);
     550         [ #  # ]:           0 :         if (err)
     551                 :           0 :                 goto out_vhdi;
     552                 :             : 
     553                 :           0 :         err = vhdi_bat_create(name->bat, name->vhd, name->index, name->files);
     554         [ #  # ]:           0 :         if (err)
     555                 :           0 :                 goto out_ft;
     556                 :             : 
     557                 :           0 :         err = vhdi_bat_write(name->bat, &bat);
     558         [ #  # ]:           0 :         if (err)
     559                 :           0 :                 goto out_ft;
     560                 :             : 
     561                 :           0 :         err = vhd_open(&vhd, name->vhd, VHD_OPEN_RDONLY);
     562         [ #  # ]:           0 :         if (err)
     563                 :           0 :                 goto out_ft;
     564                 :             : 
     565                 :           0 :         err = vhd_get_bat(&vhd);
     566         [ #  # ]:           0 :         if (err)
     567                 :           0 :                 goto out_vhd;
     568                 :             : 
     569         [ #  # ]:           0 :         for (block = 0; block < vhd.bat.entries; block++) {
     570                 :           0 :                 err = vhd_index_clone_bat_entry(name, &vhdi, &bat,
     571                 :             :                                                 &files, &vhd, block);
     572         [ #  # ]:           0 :                 if (err)
     573                 :           0 :                         goto out_bat;
     574                 :             :         }
     575                 :             : 
     576                 :           0 :         err = vhdi_bat_write(name->bat, &bat);
     577                 :             :         if (err)
     578                 :             :                 goto out_bat;
     579                 :             : 
     580                 :             :         err = 0;
     581                 :             : 
     582                 :           0 : out_bat:
     583                 :           0 :         vhd_put_bat(&vhd);
     584                 :           0 : out_vhd:
     585                 :           0 :         vhd_close(&vhd);
     586                 :           0 : out_ft:
     587                 :           0 :         vhdi_file_table_free(&files);
     588                 :           0 : out_vhdi:
     589                 :           0 :         vhdi_close(&vhdi);
     590                 :           0 : out:
     591         [ #  # ]:           0 :         if (err)
     592                 :           0 :                 unlink(name->bat);
     593                 :           0 :         free(bat.table);
     594                 :           0 :         free(pbat);
     595                 :           0 :         return err;
     596                 :             : }
     597                 :             : 
     598                 :             : static int
     599                 :           0 : vhd_index_update_bat(vhdi_name_t *name)
     600                 :             : {
     601                 :           0 :         int err;
     602                 :           0 :         uint32_t block;
     603                 :           0 :         vhdi_bat_t bat;
     604                 :           0 :         vhd_context_t vhd;
     605                 :           0 :         vhdi_context_t vhdi;
     606                 :           0 :         vhdi_file_table_t files;
     607                 :             : 
     608                 :           0 :         memset(&bat, 0, sizeof(vhdi_bat_t));
     609                 :           0 :         memset(&files, 0, sizeof(vhdi_file_table_t));
     610                 :             : 
     611                 :           0 :         err = access(name->bat, R_OK);
     612         [ #  # ]:           0 :         if (err == -1)
     613                 :           0 :                 return -errno;
     614                 :             : 
     615                 :           0 :         err = vhdi_open(&vhdi, name->index, O_RDWR);
     616         [ #  # ]:           0 :         if (err)
     617                 :           0 :                 goto out;
     618                 :             : 
     619                 :           0 :         err = vhdi_bat_load(name->bat, &bat);
     620         [ #  # ]:           0 :         if (err)
     621                 :           0 :                 goto out_vhdi;
     622                 :             : 
     623                 :           0 :         err = vhdi_file_table_load(name->files, &files);
     624         [ #  # ]:           0 :         if (err)
     625                 :           0 :                 goto out_vhdi;
     626                 :             : 
     627                 :           0 :         err = vhd_open(&vhd, name->vhd, VHD_OPEN_RDONLY);
     628         [ #  # ]:           0 :         if (err)
     629                 :           0 :                 goto out_ft;
     630                 :             : 
     631                 :           0 :         err = vhd_get_bat(&vhd);
     632         [ #  # ]:           0 :         if (err)
     633                 :           0 :                 goto out_vhd;
     634                 :             : 
     635         [ #  # ]:           0 :         for (block = 0; block < vhd.bat.entries; block++) {
     636                 :           0 :                 err = vhd_index_update_bat_entry(name, &vhdi, &bat,
     637                 :             :                                                  &files, &vhd, block);
     638         [ #  # ]:           0 :                 if (err)
     639                 :           0 :                         goto out_bat;
     640                 :             :         }
     641                 :             : 
     642                 :           0 :         err = vhdi_bat_write(name->bat, &bat);
     643                 :             :         if (err)
     644                 :             :                 goto out_bat;
     645                 :             : 
     646                 :             :         err = 0;
     647                 :             : 
     648                 :           0 : out_bat:
     649                 :           0 :         vhd_put_bat(&vhd);
     650                 :           0 : out_vhd:
     651                 :           0 :         vhd_close(&vhd);
     652                 :           0 : out_ft:
     653                 :           0 :         vhdi_file_table_free(&files);
     654                 :           0 : out_vhdi:
     655                 :           0 :         vhdi_close(&vhdi);
     656                 :           0 : out:
     657                 :           0 :         free(bat.table);
     658                 :           0 :         return err;
     659                 :             : }
     660                 :             : 
     661                 :             : static int
     662                 :           0 : vhd_index_create(vhdi_name_t *name)
     663                 :             : {
     664                 :           0 :         int err;
     665                 :           0 :         vhd_context_t ctx;
     666                 :           0 :         uint32_t block_size;
     667                 :             : 
     668   [ #  #  #  # ]:           0 :         if (!access(name->index, F_OK) || !access(name->files, F_OK))
     669                 :           0 :                 return -EEXIST;
     670                 :             : 
     671                 :           0 :         err = vhd_open(&ctx, name->vhd, VHD_OPEN_RDONLY);
     672         [ #  # ]:           0 :         if (err)
     673                 :             :                 return err;
     674                 :             : 
     675                 :           0 :         err = vhd_get_header(&ctx);
     676         [ #  # ]:           0 :         if (err) {
     677                 :           0 :                 vhd_close(&ctx);
     678                 :           0 :                 return err;
     679                 :             :         }
     680                 :             : 
     681                 :           0 :         block_size = ctx.header.block_size;
     682                 :           0 :         vhd_close(&ctx);
     683                 :             : 
     684                 :           0 :         err = vhdi_create(name->index, block_size);
     685         [ #  # ]:           0 :         if (err)
     686                 :           0 :                 goto out;
     687                 :             : 
     688                 :           0 :         err = vhdi_file_table_create(name->files);
     689         [ #  # ]:           0 :         if (err)
     690                 :           0 :                 goto out;
     691                 :             : 
     692                 :             :         err = 0;
     693                 :             : 
     694                 :             : out:
     695                 :           0 :         if (err) {
     696                 :           0 :                 unlink(name->index);
     697                 :           0 :                 unlink(name->files);
     698                 :             :         }
     699                 :             : 
     700                 :             :         return err;
     701                 :             : }
     702                 :             : 
     703                 :             : static int
     704                 :           0 : vhd_index(vhdi_name_t *name)
     705                 :             : {
     706                 :           0 :         char *parent;
     707                 :           0 :         vhd_context_t ctx;
     708                 :           0 :         uint64_t vhd_blocks;
     709                 :           0 :         uint32_t vhd_block_size;
     710                 :           0 :         int err, new_index, new_bat;
     711                 :             : 
     712                 :           0 :         parent    = NULL;
     713                 :           0 :         new_bat   = 0;
     714                 :           0 :         new_index = 0;
     715                 :             : 
     716                 :             :         /* find vhd's parent -- we only index read-only vhds */
     717                 :           0 :         err = vhd_open(&ctx, name->vhd, VHD_OPEN_RDONLY);
     718         [ #  # ]:           0 :         if (err)
     719                 :           0 :                 return err;
     720                 :             : 
     721                 :           0 :         err = vhd_parent_locator_get(&ctx, &parent);
     722                 :           0 :         vhd_close(&ctx);
     723                 :             : 
     724         [ #  # ]:           0 :         if (err)
     725                 :             :                 return err;
     726                 :             : 
     727                 :             :         /* update name to point to parent */
     728                 :           0 :         free(name->vhd);
     729                 :           0 :         name->vhd = parent;
     730                 :           0 :         parent = NULL;
     731                 :             : 
     732                 :           0 :         free(name->bat);
     733                 :           0 :         name->bat = NULL;
     734                 :           0 :         err = asprintf(&name->bat, "%s.bat", name->vhd);
     735         [ #  # ]:           0 :         if (err == -1) {
     736                 :           0 :                 free(name->bat);
     737                 :           0 :                 name->bat = NULL;
     738                 :           0 :                 return -ENOMEM;
     739                 :             :         }
     740                 :             : 
     741                 :             :         /* create index if it doesn't already exist */
     742                 :           0 :         err = access(name->index, R_OK | W_OK);
     743   [ #  #  #  # ]:           0 :         if (err == -1 && errno == ENOENT) {
     744                 :           0 :                 new_index = 1;
     745                 :           0 :                 err = vhd_index_create(name);
     746                 :             :         }
     747                 :             : 
     748         [ #  # ]:           0 :         if (err)
     749                 :             :                 return err;
     750                 :             : 
     751                 :             :         /* get basic vhd info */
     752                 :           0 :         err = vhd_open(&ctx, name->vhd, VHD_OPEN_RDONLY);
     753         [ #  # ]:           0 :         if (err)
     754                 :           0 :                 goto out;
     755                 :             : 
     756                 :           0 :         err = vhd_get_header(&ctx);
     757         [ #  # ]:           0 :         if (err) {
     758                 :           0 :                 vhd_close(&ctx);
     759                 :           0 :                 goto out;
     760                 :             :         }
     761                 :             : 
     762                 :           0 :         vhd_blocks     = ctx.header.max_bat_size;
     763                 :           0 :         vhd_block_size = ctx.header.block_size;
     764                 :             : 
     765         [ #  # ]:           0 :         if (vhd_parent_locator_get(&ctx, &parent))
     766                 :           0 :                 parent = NULL;
     767                 :             : 
     768                 :           0 :         vhd_close(&ctx);
     769                 :             : 
     770                 :             :         /* update existing bat if it exists */
     771                 :           0 :         err = vhd_index_update_bat(name);
     772         [ #  # ]:           0 :         if (err != -ENOENT)
     773                 :           0 :                 goto out;
     774                 :             : 
     775                 :           0 :         new_bat = 1;
     776                 :             : 
     777         [ #  # ]:           0 :         if (parent) {
     778                 :             :                 /* clone parent bat if it exists */
     779                 :           0 :                 err = vhd_index_clone_bat(name, parent);
     780         [ #  # ]:           0 :                 if (err != -ENOENT)
     781                 :           0 :                         goto out;
     782                 :             :         }
     783                 :             : 
     784                 :             :         /* create new bat from scratch */
     785                 :           0 :         err = vhd_index_add_bat(name, vhd_blocks, vhd_block_size);
     786         [ #  # ]:           0 :         if (err)
     787                 :           0 :                 goto out;
     788                 :             : 
     789                 :             :         err = 0;
     790                 :             : 
     791                 :           0 : out:
     792         [ #  # ]:           0 :         if (err) {
     793         [ #  # ]:           0 :                 if (new_bat)
     794                 :           0 :                         unlink(name->bat);
     795         [ #  # ]:           0 :                 if (new_index) {
     796                 :           0 :                         unlink(name->index);
     797                 :           0 :                         unlink(name->files);
     798                 :             :                 }
     799                 :             :         }
     800                 :           0 :         free(parent);
     801                 :           0 :         return err;
     802                 :             : }
     803                 :             : 
     804                 :             : static void
     805                 :           0 : vhd_index_print_summary(vhdi_name_t *name,
     806                 :             :                         uint32_t block_size, vhdi_file_table_t *files)
     807                 :             : {
     808                 :           0 :         int i;
     809                 :           0 :         char time[26], uuid[37];
     810                 :             : 
     811                 :           0 :         printf("VHD INDEX          : %s\n", name->index);
     812                 :           0 :         printf("--------------------\n");
     813                 :           0 :         printf("block size         : %u\n", block_size);
     814                 :           0 :         printf("files              : %d\n", files->entries);
     815                 :             : 
     816                 :           0 :         printf("\n");
     817         [ #  # ]:           0 :         for (i = 0; i < files->entries; i++) {
     818                 :           0 :                 uuid_unparse(files->table[i].vhd_uuid, uuid);
     819                 :           0 :                 vhd_time_to_string(files->table[i].vhd_timestamp, time);
     820                 :             : 
     821                 :           0 :                 printf("        fid 0x%04x : %s, %s, %s\n",
     822                 :           0 :                        files->table[i].file_id, files->table[i].path, uuid, time);
     823                 :             :         }
     824                 :             : 
     825                 :           0 :         printf("\n");
     826                 :           0 : }
     827                 :             : 
     828                 :             : static inline void
     829                 :           0 : vhd_index_print_bat_header(const char *name, vhdi_bat_t *bat)
     830                 :             : {
     831                 :           0 :         printf("VHD INDEX BAT      : %s\n", name);
     832                 :           0 :         printf("--------------------\n");
     833                 :           0 :         printf("blocks             : %"PRIu64"\n", bat->vhd_blocks);
     834                 :           0 :         printf("block size         : %u\n", bat->vhd_block_size);
     835                 :           0 :         printf("vhd path           : %s\n", bat->vhd_path);
     836                 :           0 :         printf("index path         : %s\n", bat->index_path);
     837                 :           0 :         printf("file table path    : %s\n", bat->file_table_path);
     838                 :           0 : }
     839                 :             : 
     840                 :             : static int
     841                 :           0 : vhd_index_print_vhd_summary(vhdi_name_t *name)
     842                 :             : {
     843                 :           0 :         int err;
     844                 :           0 :         uint32_t i;
     845                 :           0 :         vhdi_bat_t bat;
     846                 :             : 
     847                 :           0 :         err = vhdi_bat_load(name->bat, &bat);
     848         [ #  # ]:           0 :         if (err)
     849                 :           0 :                 return err;
     850                 :             : 
     851                 :           0 :         vhd_index_print_bat_header(name->bat, &bat);
     852                 :             : 
     853                 :           0 :         printf("\n");
     854         [ #  # ]:           0 :         for (i = 0; i < bat.vhd_blocks; i++)
     855                 :           0 :                 printf("      block 0x%04x : offset 0x%08x\n", i, bat.table[i]);
     856                 :             : 
     857                 :           0 :         free(bat.table);
     858                 :           0 :         return 0;
     859                 :             : }
     860                 :             : 
     861                 :             : static int
     862                 :           0 : vhd_index_print_vhd_block_summary(vhdi_name_t *name, uint32_t block)
     863                 :             : {
     864                 :           0 :         int err;
     865                 :           0 :         uint32_t i;
     866                 :           0 :         uint32_t off;
     867                 :           0 :         vhdi_bat_t bat;
     868                 :           0 :         vhdi_context_t vhdi;
     869                 :           0 :         vhdi_block_t vhdi_block;
     870                 :             : 
     871                 :           0 :         err = vhdi_bat_load(name->bat, &bat);
     872         [ #  # ]:           0 :         if (err)
     873                 :           0 :                 return err;
     874                 :             : 
     875                 :           0 :         vhd_index_print_bat_header(name->bat, &bat);
     876                 :             : 
     877         [ #  # ]:           0 :         if (block > bat.vhd_blocks) {
     878                 :           0 :                 printf("block %u past end of bat (%"PRIu64")\n",
     879                 :             :                        block, bat.vhd_blocks);
     880                 :           0 :                 err = -EINVAL;
     881                 :           0 :                 goto out;
     882                 :             :         }
     883                 :             : 
     884                 :           0 :         off = bat.table[block];
     885         [ #  # ]:           0 :         if (off == DD_BLK_UNUSED) {
     886                 :           0 :                 printf("block %u is unallocated\n", block);
     887                 :           0 :                 err = 0;
     888                 :           0 :                 goto out;
     889                 :             :         }
     890                 :             : 
     891                 :           0 :         err = vhdi_open(&vhdi, name->index, O_RDWR);
     892         [ #  # ]:           0 :         if (err)
     893                 :           0 :                 goto out;
     894                 :             : 
     895                 :           0 :         err = vhdi_read_block(&vhdi, &vhdi_block, off);
     896                 :           0 :         vhdi_close(&vhdi);
     897         [ #  # ]:           0 :         if (err)
     898                 :           0 :                 goto out;
     899                 :             : 
     900                 :           0 :         printf("\nBLOCK 0x%08x\n", block);
     901         [ #  # ]:           0 :         for (i = 0; i < vhdi_block.entries; i++)
     902                 :           0 :                 printf("        sec 0x%04x : fid 0x%04x, offset 0x%08x\n", i,
     903                 :             :                        vhdi_block.table[i].file_id,
     904                 :           0 :                        vhdi_block.table[i].offset);
     905                 :             : 
     906                 :           0 :         free(vhdi_block.table);
     907                 :           0 :         err = 0;
     908                 :             : 
     909                 :           0 : out:
     910                 :           0 :         free(bat.table);
     911                 :           0 :         return err;
     912                 :             : }
     913                 :             : 
     914                 :             : static int
     915                 :           0 : vhd_index_summary(vhdi_name_t *name, uint32_t block)
     916                 :             : {
     917                 :           0 :         int err;
     918                 :           0 :         uint32_t block_size;
     919                 :           0 :         vhdi_context_t vhdi;
     920                 :           0 :         vhdi_file_table_t files;
     921                 :             : 
     922                 :           0 :         memset(&files, 0, sizeof(vhdi_file_table_t));
     923                 :             : 
     924                 :           0 :         err = vhdi_open(&vhdi, name->index, O_RDWR);
     925         [ #  # ]:           0 :         if (err)
     926                 :           0 :                 return err;
     927                 :             : 
     928                 :           0 :         block_size = vhdi.vhd_block_size;
     929                 :           0 :         vhdi_close(&vhdi);
     930                 :             : 
     931                 :           0 :         err = vhdi_file_table_load(name->files, &files);
     932         [ #  # ]:           0 :         if (err)
     933                 :             :                 return err;
     934                 :             : 
     935                 :           0 :         vhd_index_print_summary(name, block_size, &files);
     936                 :             : 
     937         [ #  # ]:           0 :         if (name->vhd) {
     938         [ #  # ]:           0 :                 if (block == (uint32_t)-1)
     939                 :           0 :                         err = vhd_index_print_vhd_summary(name);
     940                 :             :                 else
     941                 :           0 :                         err = vhd_index_print_vhd_block_summary(name, block);
     942                 :             : 
     943         [ #  # ]:           0 :                 if (err)
     944                 :           0 :                         goto out;
     945                 :             :         }
     946                 :             : 
     947                 :             :         err = 0;
     948                 :             : 
     949                 :           0 : out:
     950                 :           0 :         vhdi_file_table_free(&files);
     951                 :             :         return err;
     952                 :             : }
     953                 :             : 
     954                 :             : int
     955                 :           0 : main(int argc, char *argv[])
     956                 :             : {
     957                 :           0 :         int err;
     958                 :           0 :         uint32_t block;
     959                 :           0 :         vhdi_name_t name;
     960                 :           0 :         char *vhd, *index;
     961                 :           0 :         int c, update, summary;
     962                 :             : 
     963                 :           0 :         vhd     = NULL;
     964                 :           0 :         index   = NULL;
     965                 :           0 :         block   = (uint32_t)-1;
     966                 :           0 :         update  = 0;
     967                 :           0 :         summary = 0;
     968                 :             : 
     969         [ #  # ]:           0 :         while ((c = getopt(argc, argv, "i:v:s:b:h")) != -1) {
     970   [ #  #  #  #  :           0 :                 switch (c) {
                      # ]
     971                 :           0 :                 case 'i':
     972                 :           0 :                         index   = optarg;
     973                 :           0 :                         update  = 1;
     974                 :           0 :                         break;
     975                 :             : 
     976                 :           0 :                 case 'v':
     977                 :           0 :                         vhd     = optarg;
     978                 :           0 :                         break;
     979                 :             : 
     980                 :           0 :                 case 's':
     981                 :           0 :                         index   = optarg;
     982                 :           0 :                         summary = 1;
     983                 :           0 :                         break;
     984                 :             : 
     985                 :           0 :                 case 'b':
     986                 :           0 :                         block   = strtoul(optarg, NULL, 10);
     987                 :           0 :                         break;
     988                 :             : 
     989                 :           0 :                 default:
     990                 :           0 :                         usage();
     991                 :             :                 }
     992                 :             :         }
     993                 :             : 
     994         [ #  # ]:           0 :         if (optind != argc)
     995                 :           0 :                 usage();
     996                 :             : 
     997         [ #  # ]:           0 :         if (!(update ^ summary))
     998                 :           0 :                 usage();
     999                 :             : 
    1000   [ #  #  #  # ]:           0 :         if (block != (uint32_t)-1 && (!summary || !vhd))
    1001                 :           0 :                 usage();
    1002                 :             : 
    1003                 :           0 :         err = vhd_index_get_name(index, vhd, &name);
    1004         [ #  # ]:           0 :         if (err)
    1005                 :           0 :                 goto out;
    1006                 :             : 
    1007         [ #  # ]:           0 :         if (summary)
    1008                 :           0 :                 err = vhd_index_summary(&name, block);
    1009         [ #  # ]:           0 :         else if (update) {
    1010         [ #  # ]:           0 :                 if (!vhd)
    1011                 :           0 :                         usage();
    1012                 :             : 
    1013                 :           0 :                 err = vhd_index(&name);
    1014                 :             :         }
    1015                 :             : 
    1016                 :           0 : out:
    1017                 :           0 :         vhd_index_free_name(&name);
    1018                 :           0 :         return -err;
    1019                 :             : }
        

Generated by: LCOV version 2.0-1