LCOV - code coverage report
Current view: top level - vhd/lib - vhd-util-coalesce.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 123 0.0 %
Date: 2026-02-26 14:46:47 Functions: 0 5 0.0 %
Branches: 0 86 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 <errno.h>
      36                 :            : #include <fcntl.h>
      37                 :            : #include <stdio.h>
      38                 :            : #include <stdlib.h>
      39                 :            : #include <unistd.h>
      40                 :            : #include <limits.h>
      41                 :            : 
      42                 :            : #include "libvhd.h"
      43                 :            : #include "canonpath.h"
      44                 :            : 
      45                 :            : static int
      46                 :          0 : __raw_io_write(int fd, char* buf, uint64_t sec, uint32_t secs)
      47                 :            : {
      48                 :            :         off64_t off;
      49                 :            :         ssize_t ret;
      50                 :            : 
      51                 :          0 :         errno = 0;
      52                 :          0 :         off = lseek64(fd, (off64_t)vhd_sectors_to_bytes(sec), SEEK_SET);
      53         [ #  # ]:          0 :         if (off == (off64_t)-1) {
      54                 :          0 :                 printf("raw parent: seek(0x%08"PRIx64") failed: %d\n",
      55                 :          0 :                        vhd_sectors_to_bytes(sec), -errno);
      56                 :          0 :                 return -errno;
      57                 :            :         }
      58                 :            : 
      59                 :          0 :         ret = write(fd, buf, vhd_sectors_to_bytes(secs));
      60         [ #  # ]:          0 :         if (ret == vhd_sectors_to_bytes(secs))
      61                 :            :                 return 0;
      62                 :            : 
      63                 :          0 :         printf("raw parent: write of 0x%"PRIx64" returned %zd, errno: %d\n",
      64                 :          0 :                vhd_sectors_to_bytes(secs), ret, -errno);
      65         [ #  # ]:          0 :         return (errno ? -errno : -EIO);
      66                 :            : }
      67                 :            : 
      68                 :            : /**
      69                 :            :  * Coalesce a VHD allocation block
      70                 :            :  *
      71                 :            :  * @param[in] vhd the VHD being coalesced
      72                 :            :  * @param[in] parent the VHD to coalesce to unless raw
      73                 :            :  * @param[in] parent_fd raw FD to coalesce to unless VHD parent
      74                 :            :  * @param[in] parent block the allocation block number to coalese
      75                 :            :  * @return the number of sectors coalesced or negative errno on failure
      76                 :            :  */
      77                 :            : static int64_t
      78                 :          0 : vhd_util_coalesce_block(vhd_context_t *vhd, vhd_context_t *parent,
      79                 :            :                         int parent_fd, uint64_t block)
      80                 :            : {
      81                 :            :         int err;
      82                 :            :         uint32_t i;
      83                 :          0 :         int64_t coalesced_size = 0;
      84                 :            :         char *buf;
      85                 :            :         char *map;
      86                 :            :         uint64_t sec, secs;
      87                 :            : 
      88                 :          0 :         buf = NULL;
      89                 :          0 :         map = NULL;
      90                 :          0 :         sec = block * vhd->spb;
      91                 :            : 
      92         [ #  # ]:          0 :         if (vhd->bat.bat[block] == DD_BLK_UNUSED)
      93                 :          0 :                 return 0;
      94                 :            : 
      95 [ #  # ][ #  # ]:          0 :         if (vhd_has_batmap(vhd) && vhd_batmap_test(vhd, &vhd->batmap, block)) {
      96                 :          0 :                 err = vhd_read_block(vhd, block, &buf);
      97         [ #  # ]:          0 :                 if (err)
      98                 :            :                         goto done;
      99                 :            : 
     100         [ #  # ]:          0 :                 if (parent->file)
     101                 :          0 :                         err = vhd_io_write(parent, buf, sec, vhd->spb);
     102                 :            :                 else
     103                 :          0 :                         err = __raw_io_write(parent_fd, buf, sec, vhd->spb);
     104                 :            : 
     105         [ #  # ]:          0 :                 if (err == 0)
     106                 :          0 :                         coalesced_size = vhd->spb;
     107                 :            : 
     108                 :            :                 goto done;
     109                 :            :         }
     110                 :            : 
     111                 :          0 :         err = vhd_read_bitmap(vhd, block, &map);
     112         [ #  # ]:          0 :         if (err)
     113                 :            :                 goto done;
     114                 :            : 
     115                 :          0 :         err = posix_memalign((void *)&buf, 4096, vhd->header.block_size);
     116         [ #  # ]:          0 :         if (err) {
     117                 :          0 :                 err = -err;
     118                 :          0 :                 goto done;
     119                 :            :         }
     120                 :            : 
     121         [ #  # ]:          0 :         for (i = 0; i < vhd->spb; i++) {
     122         [ #  # ]:          0 :                 if (!vhd_bitmap_test(vhd, map, i))
     123                 :          0 :                         continue;
     124                 :            : 
     125         [ #  # ]:          0 :                 for (secs = 0; i + secs < vhd->spb; secs++)
     126         [ #  # ]:          0 :                         if (!vhd_bitmap_test(vhd, map, i + secs))
     127                 :            :                                 break;
     128                 :            : 
     129                 :          0 :                 err = vhd_read_at(vhd, block, i, vhd_sectors_to_bytes(secs),
     130                 :          0 :                                   buf + vhd_sectors_to_bytes(i));
     131         [ #  # ]:          0 :                 if (err)
     132                 :            :                         goto done;
     133                 :            : 
     134         [ #  # ]:          0 :                 if (parent->file)
     135                 :          0 :                         err = vhd_io_write(parent,
     136                 :          0 :                                            buf + vhd_sectors_to_bytes(i),
     137                 :            :                                            sec + i, secs);
     138                 :            :                 else
     139                 :          0 :                         err = __raw_io_write(parent_fd,
     140                 :          0 :                                              buf + vhd_sectors_to_bytes(i),
     141                 :            :                                              sec + i, secs);
     142         [ #  # ]:          0 :                 if (err)
     143                 :            :                         goto done;
     144                 :            : 
     145                 :          0 :                 coalesced_size += (int64_t)secs;
     146                 :          0 :                 i += (uint32_t)secs;
     147                 :            :         }
     148                 :            : 
     149                 :            :         err = 0;
     150                 :            : 
     151                 :            : done:
     152                 :          0 :         free(buf);
     153                 :          0 :         free(map);
     154         [ #  # ]:          0 :         if (err < 0)
     155                 :          0 :                 return err;
     156                 :            : 
     157                 :            :         return coalesced_size;
     158                 :            : }
     159                 :            : 
     160                 :            : /**
     161                 :            :  * Coalesce VHD to its immediate parent
     162                 :            :  *
     163                 :            :  * @param[in] from the VHD to coalesce
     164                 :            :  * @param[in] to the VHD to coalesce to or NULL if raw
     165                 :            :  * @param[in] to_fd the raws file to coalesce to or NULL if to is to be used
     166                 :            :  * @param[in] progess whether to report progress as the operation is being performed
     167                 :            :  * @return positive number of sectors coalesced or negative errno in the case of failure
     168                 :            :  */
     169                 :            : static int64_t
     170                 :          0 : vhd_util_coalesce_onto(vhd_context_t *from,
     171                 :            :                        vhd_context_t *to, int to_fd, int progress)
     172                 :            : {
     173                 :            :         int i;
     174                 :            :         int64_t err;
     175                 :          0 :         int64_t coalesced_size = 0;
     176                 :            : 
     177                 :          0 :         err = vhd_get_bat(from);
     178         [ #  # ]:          0 :         if (err)
     179                 :            :                 goto out;
     180                 :            : 
     181         [ #  # ]:          0 :         if (vhd_has_batmap(from)) {
     182                 :          0 :                 err = vhd_get_batmap(from);
     183         [ #  # ]:          0 :                 if (err)
     184                 :            :                         goto out;
     185                 :            :         }
     186                 :            : 
     187         [ #  # ]:          0 :         for (i = 0; i < from->bat.entries; i++) {
     188         [ #  # ]:          0 :                 if (progress) {
     189                 :          0 :                         printf("\r%6.2f%%",
     190                 :          0 :                                ((float)i / (float)from->bat.entries) * 100.00);
     191                 :          0 :                         fflush(stdout);
     192                 :            :                 }
     193                 :          0 :                 err = vhd_util_coalesce_block(from, to, to_fd, (uint64_t)i);
     194         [ #  # ]:          0 :                 if (err < 0)
     195                 :            :                         goto out;
     196                 :            : 
     197                 :          0 :                 coalesced_size += err;
     198                 :            :         }
     199                 :            : 
     200                 :          0 :         err = 0;
     201                 :            : 
     202         [ #  # ]:          0 :         if (progress)
     203                 :            :                 printf("\r100.00%%\n");
     204                 :            : 
     205                 :            : out:
     206         [ #  # ]:          0 :         if (err < 0)
     207                 :            :                 return err;
     208                 :            : 
     209                 :          0 :         return coalesced_size;
     210                 :            : }
     211                 :            : 
     212                 :            : /**
     213                 :            :  * Coalesce the VHD to its immediate parent
     214                 :            :  *
     215                 :            :  * @param[in] name the name (path) of the VHD to coalesce
     216                 :            :  * @param[in] sparse whether the parent VHD should be written sparsely
     217                 :            :  * @param[in] progess whether to report progress as the operation is being performed
     218                 :            :  * @return positive number of sectors coalesced or negative errno in the case of failure
     219                 :            :  */
     220                 :            : static int64_t
     221                 :          0 : vhd_util_coalesce_parent(const char *name, int sparse, int progress)
     222                 :            : {
     223                 :            :         char *pname;
     224                 :            :         int64_t err;
     225                 :            :         int parent_fd;
     226                 :            :         vhd_context_t vhd, parent;
     227                 :            : 
     228                 :          0 :         parent_fd   = -1;
     229                 :          0 :         parent.file = NULL;
     230                 :            : 
     231                 :          0 :         err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
     232         [ #  # ]:          0 :         if (err) {
     233                 :            :                 printf("error opening %s: %" PRId64 "\n", name, err);
     234                 :          0 :                 return err;
     235                 :            :         }
     236                 :            : 
     237         [ #  # ]:          0 :         if (vhd.footer.type != HD_TYPE_DIFF) {
     238                 :            :                 printf("coalescing of non-differencing disks is not supported\n");
     239                 :          0 :                 vhd_close(&vhd);
     240                 :            :                 return -EINVAL;
     241                 :            :         }
     242                 :            : 
     243                 :          0 :         err = vhd_parent_locator_get(&vhd, &pname);
     244         [ #  # ]:          0 :         if (err) {
     245                 :            :                 printf("error finding %s parent: %" PRId64 "\n", name, err);
     246                 :          0 :                 vhd_close(&vhd);
     247                 :            :                 return err;
     248                 :            :         }
     249                 :            : 
     250         [ #  # ]:          0 :         if (vhd_parent_raw(&vhd)) {
     251                 :          0 :                 parent_fd = open_optional_odirect(pname, O_RDWR | O_DIRECT | O_LARGEFILE, 0644);
     252         [ #  # ]:          0 :                 if (parent_fd == -1) {
     253                 :          0 :                         err = -errno;
     254                 :          0 :                         printf("failed to open parent %s: %" PRId64 "\n", pname, err);
     255                 :          0 :                         free(pname);
     256                 :          0 :                         vhd_close(&vhd);
     257                 :            :                         return err;
     258                 :            :                 }
     259                 :            :         } else {
     260         [ #  # ]:          0 :                 int flags = (sparse ? VHD_OPEN_IO_WRITE_SPARSE : 0);
     261         [ #  # ]:          0 :                 if (sparse) printf("opening for sparse writes\n");
     262                 :          0 :                 err = vhd_open(&parent, pname, VHD_OPEN_RDWR | flags);
     263         [ #  # ]:          0 :                 if (err) {
     264                 :          0 :                         printf("error opening %s: %" PRId64 "\n", pname, err);
     265                 :          0 :                         free(pname);
     266                 :          0 :                         vhd_close(&vhd);
     267                 :            :                         return err;
     268                 :            :                 }
     269                 :            :         }
     270                 :            : 
     271                 :          0 :         err = vhd_util_coalesce_onto(&vhd, &parent, parent_fd, progress);
     272                 :            : 
     273                 :          0 :         free(pname);
     274                 :          0 :         vhd_close(&vhd);
     275         [ #  # ]:          0 :         if (parent.file)
     276                 :          0 :                 vhd_close(&parent);
     277                 :            :         else
     278                 :          0 :                 close(parent_fd);
     279                 :          0 :         return err;
     280                 :            : }
     281                 :            : 
     282                 :            : int
     283                 :          0 : vhd_util_coalesce(int argc, char **argv)
     284                 :            : {
     285                 :            :         char *name;
     286                 :            :         int c, progress, sparse;
     287                 :            :         int64_t result;
     288                 :            : 
     289                 :          0 :         name        = NULL;
     290                 :          0 :         sparse      = 0;
     291                 :          0 :         progress    = 0;
     292                 :            : 
     293         [ #  # ]:          0 :         if (!argc || !argv)
     294                 :            :                 goto usage;
     295                 :            : 
     296                 :          0 :         optind = 0;
     297         [ #  # ]:          0 :         while ((c = getopt(argc, argv, "n:o:a:x:sph")) != -1) {
     298   [ #  #  #  # ]:          0 :                 switch (c) {
     299                 :            :                 case 'n':
     300                 :          0 :                         name = optarg;
     301                 :          0 :                         break;
     302                 :            :                 case 's':
     303                 :            :                         sparse = 1;
     304                 :            :                         break;
     305                 :            :                 case 'p':
     306                 :          0 :                         progress = 1;
     307                 :          0 :                         break;
     308                 :            :                 case 'h':
     309                 :            :                 default:
     310                 :            :                         goto usage;
     311                 :            :                 }
     312                 :            :         }
     313                 :            : 
     314 [ #  # ][ #  # ]:          0 :         if (!name || optind != argc)
     315                 :            :                 goto usage;
     316                 :            : 
     317                 :          0 :         result = vhd_util_coalesce_parent(name, sparse, progress);
     318                 :            : 
     319         [ #  # ]:          0 :         if (result < 0) {
     320                 :            :                 /* -ve errors will be in range for int */
     321                 :          0 :                 printf("error coalescing: %d\n", (int)result);
     322                 :          0 :                 return result;
     323                 :            :         }
     324                 :            : 
     325                 :            :         printf("Coalesced %" PRId64 " sectors", result);
     326                 :          0 :         return 0;
     327                 :            : 
     328                 :            : usage:
     329                 :            :         printf("options: <-n name> "
     330                 :            :                "[-s sparse] [-p progress] "
     331                 :            :                "[-h help]\n");
     332                 :          0 :         return -EINVAL;
     333                 :            : }

Generated by: LCOV version 1.13