LCOV - code coverage report
Current view: top level - vhd - vhd-index.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 442 0.0 %
Date: 2025-07-10 10:47:11 Functions: 0 28 0.0 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016, Citrix Systems, Inc.
       3                 :            :  *
       4                 :            :  * All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions are met:
       8                 :            :  * 
       9                 :            :  *  1. Redistributions of source code must retain the above copyright
      10                 :            :  *     notice, this list of conditions and the following disclaimer.
      11                 :            :  *  2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *     notice, this list of conditions and the following disclaimer in the
      13                 :            :  *     documentation and/or other materials provided with the distribution.
      14                 :            :  *  3. Neither the name of the copyright holder nor the names of its 
      15                 :            :  *     contributors may be used to endorse or promote products derived from 
      16                 :            :  *     this software without specific prior written permission.
      17                 :            :  *
      18                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19                 :            :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      21                 :            :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
      22                 :            :  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      23                 :            :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      24                 :            :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      25                 :            :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      26                 :            :  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      27                 :            :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28                 :            :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #ifdef HAVE_CONFIG_H
      32                 :            : #include "config.h"
      33                 :            : #endif
      34                 :            : 
      35                 :            : #include <stdio.h>
      36                 :            : #include <errno.h>
      37                 :            : #include <fcntl.h>
      38                 :            : #include <stdlib.h>
      39                 :            : #include <unistd.h>
      40                 :            : #include <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                 :            :         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                 :            :         int err, len;
      72                 :            : 
      73                 :            :         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                 :            : 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                 :            :         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                 :            :         char *path, __path[PATH_MAX];
     157                 :            :         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                 :            :         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                 :            :         char *map;
     198                 :            :         vhdi_file_id_t fid;
     199                 :            :         uint32_t i, count, off;
     200                 :            :         vhdi_block_t vhdi_block;
     201                 :            :         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                 :            :                 goto out;
     218                 :            : 
     219                 :          0 :         err = vhd_index_get_file_id(name, vhd->file, files, &fid);
     220                 :          0 :         if (err)
     221                 :            :                 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                 :            :                         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                 :            :                         uint32_t location;
     245                 :            : 
     246                 :          0 :                         err = vhdi_append_block(vhdi, &vhdi_block, &location);
     247                 :          0 :                         if (err)
     248                 :            :                                 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                 :            :                                 goto out;
     256                 :            :                 }
     257                 :            :         }
     258                 :            : 
     259                 :          0 :         if (count == vhd->spb)
     260                 :          0 :                 *finished = 1;
     261                 :            : 
     262                 :            :         err = 0;
     263                 :            : 
     264                 :            : 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                 :            :         char *map;
     277                 :            :         int err, update;
     278                 :            :         uint32_t i, off;
     279                 :            :         vhdi_file_id_t fid;
     280                 :            :         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                 :            :                 goto out;
     295                 :            : 
     296                 :          0 :         err = vhd_index_get_file_id(name, vhd->file, files, &fid);
     297                 :          0 :         if (err)
     298                 :            :                 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                 :            :                         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                 :            :                 uint32_t location;
     315                 :            : 
     316                 :          0 :                 err = vhdi_append_block(vhdi, &vhdi_block, &location);
     317                 :          0 :                 if (err)
     318                 :            :                         goto out;
     319                 :            : 
     320                 :          0 :                 bat->table[block] = location;
     321                 :            :         }
     322                 :            : 
     323                 :            :         err = 0;
     324                 :            : 
     325                 :            : 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                 :            :         char *map;
     338                 :            :         int err, update;
     339                 :            :         uint32_t i, off;
     340                 :            :         vhdi_file_id_t fid;
     341                 :            :         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                 :            :                 goto out;
     356                 :            : 
     357                 :          0 :         err = vhd_index_get_file_id(name, vhd->file, files, &fid);
     358                 :          0 :         if (err)
     359                 :            :                 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                 :            :                         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                 :            :                 uint32_t location;
     380                 :            : 
     381                 :          0 :                 err = vhdi_append_block(vhdi, &vhdi_block, &location);
     382                 :          0 :                 if (err)
     383                 :            :                         goto out;
     384                 :            : 
     385                 :          0 :                 bat->table[block] = location;
     386                 :            :         }
     387                 :            : 
     388                 :            :         err = 0;
     389                 :            : 
     390                 :            : 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                 :            :         int err;
     402                 :            :         vhdi_bat_t bat;
     403                 :            :         vhd_context_t vhd;
     404                 :            :         vhdi_context_t vhdi;
     405                 :            :         vhdi_file_table_t files;
     406                 :            :         char *vhd_file, *finished;
     407                 :            :         uint32_t block, remaining;
     408                 :            : 
     409                 :            :         memset(&bat, 0, sizeof(vhdi_bat_t));
     410                 :            :         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                 :            :                 return err;
     429                 :            :         }
     430                 :            : 
     431                 :          0 :         err = vhdi_bat_create(name->bat, name->vhd, name->index, name->files);
     432                 :          0 :         if (err)
     433                 :            :                 goto out;
     434                 :            : 
     435                 :          0 :         bat.table = calloc(vhd_blocks, sizeof(uint32_t));
     436                 :          0 :         if (!bat.table) {
     437                 :            :                 err = -ENOMEM;
     438                 :            :                 goto out;
     439                 :            :         }
     440                 :            : 
     441                 :          0 :         vhd_file = strdup(name->vhd);
     442                 :          0 :         if (!vhd_file)
     443                 :            :                 goto out;
     444                 :            : 
     445                 :          0 :         remaining = vhd_blocks;
     446                 :          0 :         finished  = calloc(remaining, sizeof(char));
     447                 :          0 :         if (!finished) {
     448                 :            :                 err = -ENOMEM;
     449                 :            :                 goto out;
     450                 :            :         }
     451                 :            : 
     452                 :            :         for (;;) {
     453                 :          0 :                 err = vhd_open(&vhd, vhd_file, VHD_OPEN_RDONLY);
     454                 :          0 :                 if (err)
     455                 :            :                         goto out;
     456                 :            : 
     457                 :          0 :                 err = vhd_get_bat(&vhd);
     458                 :          0 :                 if (err)
     459                 :            :                         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                 :            :                                 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                 :            :                         break;
     482                 :            :                 }
     483                 :            : 
     484                 :          0 :                 err = vhd_parent_locator_get(&vhd, &vhd_file);
     485                 :            :                 if (err)
     486                 :            :                         goto out_bat;
     487                 :            : 
     488                 :            :         out_bat:
     489                 :          0 :                 vhd_put_bat(&vhd);
     490                 :            :         out_vhd:
     491                 :          0 :                 vhd_close(&vhd);
     492                 :          0 :                 if (err)
     493                 :            :                         goto out;
     494                 :            :         } 
     495                 :            : 
     496                 :          0 :         err = vhdi_bat_write(name->bat, &bat);
     497                 :          0 :         if (err)
     498                 :            :                 goto out;
     499                 :            : 
     500                 :          0 :         err = 0;
     501                 :            : 
     502                 :            : 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                 :            :         int err;
     519                 :          0 :         char *pbat = NULL;
     520                 :            :         uint32_t block;
     521                 :            :         vhdi_bat_t bat;
     522                 :            :         vhd_context_t vhd;
     523                 :            :         vhdi_context_t vhdi;
     524                 :            :         vhdi_file_table_t files;
     525                 :            : 
     526                 :            :         memset(&bat, 0, sizeof(vhdi_bat_t));
     527                 :            :         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                 :            :                 goto out;
     544                 :            : 
     545                 :          0 :         err = vhdi_bat_load(pbat, &bat);
     546                 :          0 :         if (err)
     547                 :            :                 goto out_vhdi;
     548                 :            : 
     549                 :          0 :         err = vhdi_file_table_load(name->files, &files);
     550                 :          0 :         if (err)
     551                 :            :                 goto out_vhdi;
     552                 :            : 
     553                 :          0 :         err = vhdi_bat_create(name->bat, name->vhd, name->index, name->files);
     554                 :          0 :         if (err)
     555                 :            :                 goto out_ft;
     556                 :            : 
     557                 :          0 :         err = vhdi_bat_write(name->bat, &bat);
     558                 :          0 :         if (err)
     559                 :            :                 goto out_ft;
     560                 :            : 
     561                 :          0 :         err = vhd_open(&vhd, name->vhd, VHD_OPEN_RDONLY);
     562                 :          0 :         if (err)
     563                 :            :                 goto out_ft;
     564                 :            : 
     565                 :          0 :         err = vhd_get_bat(&vhd);
     566                 :          0 :         if (err)
     567                 :            :                 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                 :            :                         goto out_bat;
     574                 :            :         }
     575                 :            : 
     576                 :          0 :         err = vhdi_bat_write(name->bat, &bat);
     577                 :          0 :         if (err)
     578                 :            :                 goto out_bat;
     579                 :            : 
     580                 :          0 :         err = 0;
     581                 :            : 
     582                 :            : out_bat:
     583                 :          0 :         vhd_put_bat(&vhd);
     584                 :            : out_vhd:
     585                 :          0 :         vhd_close(&vhd);
     586                 :            : out_ft:
     587                 :          0 :         vhdi_file_table_free(&files);
     588                 :            : out_vhdi:
     589                 :          0 :         vhdi_close(&vhdi);
     590                 :            : 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                 :            :         int err;
     602                 :            :         uint32_t block;
     603                 :            :         vhdi_bat_t bat;
     604                 :            :         vhd_context_t vhd;
     605                 :            :         vhdi_context_t vhdi;
     606                 :            :         vhdi_file_table_t files;
     607                 :            : 
     608                 :            :         memset(&bat, 0, sizeof(vhdi_bat_t));
     609                 :            :         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                 :            :                 goto out;
     618                 :            : 
     619                 :          0 :         err = vhdi_bat_load(name->bat, &bat);
     620                 :          0 :         if (err)
     621                 :            :                 goto out_vhdi;
     622                 :            : 
     623                 :          0 :         err = vhdi_file_table_load(name->files, &files);
     624                 :          0 :         if (err)
     625                 :            :                 goto out_vhdi;
     626                 :            : 
     627                 :          0 :         err = vhd_open(&vhd, name->vhd, VHD_OPEN_RDONLY);
     628                 :          0 :         if (err)
     629                 :            :                 goto out_ft;
     630                 :            : 
     631                 :          0 :         err = vhd_get_bat(&vhd);
     632                 :          0 :         if (err)
     633                 :            :                 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                 :            :                         goto out_bat;
     640                 :            :         }
     641                 :            : 
     642                 :          0 :         err = vhdi_bat_write(name->bat, &bat);
     643                 :          0 :         if (err)
     644                 :            :                 goto out_bat;
     645                 :            : 
     646                 :          0 :         err = 0;
     647                 :            : 
     648                 :            : out_bat:
     649                 :          0 :         vhd_put_bat(&vhd);
     650                 :            : out_vhd:
     651                 :          0 :         vhd_close(&vhd);
     652                 :            : out_ft:
     653                 :          0 :         vhdi_file_table_free(&files);
     654                 :            : out_vhdi:
     655                 :          0 :         vhdi_close(&vhdi);
     656                 :            : 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                 :            :         int err;
     665                 :            :         vhd_context_t ctx;
     666                 :            :         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                 :            :                 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                 :            :                 goto out;
     687                 :            : 
     688                 :          0 :         err = vhdi_file_table_create(name->files);
     689                 :          0 :         if (err)
     690                 :            :                 goto out;
     691                 :            : 
     692                 :          0 :         err = 0;
     693                 :            : 
     694                 :            : out:
     695                 :          0 :         if (err) {
     696                 :          0 :                 unlink(name->index);
     697                 :          0 :                 unlink(name->files);
     698                 :            :         }
     699                 :            : 
     700                 :          0 :         return err;
     701                 :            : }
     702                 :            : 
     703                 :            : static int
     704                 :          0 : vhd_index(vhdi_name_t *name)
     705                 :            : {
     706                 :            :         char *parent;
     707                 :            :         vhd_context_t ctx;
     708                 :            :         uint64_t vhd_blocks;
     709                 :            :         uint32_t vhd_block_size;
     710                 :            :         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                 :            :                 goto out;
     755                 :            : 
     756                 :          0 :         err = vhd_get_header(&ctx);
     757                 :          0 :         if (err) {
     758                 :          0 :                 vhd_close(&ctx);
     759                 :            :                 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                 :            :                 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                 :            :                         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                 :            :                 goto out;
     788                 :            : 
     789                 :          0 :         err = 0;
     790                 :            : 
     791                 :            : 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                 :            :         int i;
     809                 :            :         char time[26], uuid[37];
     810                 :            : 
     811                 :          0 :         printf("VHD INDEX          : %s\n", name->index);
     812                 :            :         printf("--------------------\n");
     813                 :            :         printf("block size         : %u\n", block_size);
     814                 :          0 :         printf("files              : %d\n", files->entries);
     815                 :            : 
     816                 :            :         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                 :            :         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                 :            :         printf("VHD INDEX BAT      : %s\n", name);
     832                 :            :         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                 :            :         int err;
     844                 :            :         uint32_t i;
     845                 :            :         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                 :            :         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                 :            :         int err;
     865                 :            :         uint32_t i;
     866                 :            :         uint32_t off;
     867                 :            :         vhdi_bat_t bat;
     868                 :            :         vhdi_context_t vhdi;
     869                 :            :         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                 :            :                 err = -EINVAL;
     881                 :            :                 goto out;
     882                 :            :         }
     883                 :            : 
     884                 :          0 :         off = bat.table[block];
     885                 :          0 :         if (off == DD_BLK_UNUSED) {
     886                 :            :                 printf("block %u is unallocated\n", block);
     887                 :            :                 err = 0;
     888                 :            :                 goto out;
     889                 :            :         }
     890                 :            : 
     891                 :          0 :         err = vhdi_open(&vhdi, name->index, O_RDWR);
     892                 :          0 :         if (err)
     893                 :            :                 goto out;
     894                 :            : 
     895                 :          0 :         err = vhdi_read_block(&vhdi, &vhdi_block, off);
     896                 :          0 :         vhdi_close(&vhdi);
     897                 :          0 :         if (err)
     898                 :            :                 goto out;
     899                 :            : 
     900                 :            :         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                 :            : 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                 :            :         int err;
     918                 :            :         uint32_t block_size;
     919                 :            :         vhdi_context_t vhdi;
     920                 :            :         vhdi_file_table_t files;
     921                 :            : 
     922                 :            :         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                 :            :                         goto out;
     945                 :            :         }
     946                 :            : 
     947                 :            :         err = 0;
     948                 :            : 
     949                 :            : out:
     950                 :          0 :         vhdi_file_table_free(&files);
     951                 :            :         return err;
     952                 :            : }
     953                 :            : 
     954                 :            : int
     955                 :          0 : main(int argc, char *argv[])
     956                 :            : {
     957                 :            :         int err;
     958                 :            :         uint32_t block;
     959                 :            :         vhdi_name_t name;
     960                 :            :         char *vhd, *index;
     961                 :            :         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                 :            :                 case 'i':
     972                 :          0 :                         index   = optarg;
     973                 :          0 :                         update  = 1;
     974                 :          0 :                         break;
     975                 :            : 
     976                 :            :                 case 'v':
     977                 :          0 :                         vhd     = optarg;
     978                 :          0 :                         break;
     979                 :            : 
     980                 :            :                 case 's':
     981                 :          0 :                         index   = optarg;
     982                 :          0 :                         summary = 1;
     983                 :          0 :                         break;
     984                 :            : 
     985                 :            :                 case 'b':
     986                 :          0 :                         block   = strtoul(optarg, NULL, 10);
     987                 :          0 :                         break;
     988                 :            : 
     989                 :            :                 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                 :            :                 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                 :            : out:
    1017                 :          0 :         vhd_index_free_name(&name);
    1018                 :          0 :         return -err;
    1019                 :            : }

Generated by: LCOV version 1.13