LCOV - code coverage report
Current view: top level - vhd/lib - vhd-util-coalesce.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 165 0
Test Date: 2026-06-26 00:00:00 Functions: 0.0 % 5 0
Branches: 0.0 % 84 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                 :           0 :         off64_t off;
      49                 :           0 :         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                 :           0 :         int err;
      82                 :           0 :         uint32_t i;
      83                 :           0 :         int64_t coalesced_size = 0;
      84                 :           0 :         char *buf;
      85                 :           0 :         char *map;
      86                 :           0 :         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                 :           0 :                         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                 :           0 :                 goto done;
     109                 :             :         }
     110                 :             : 
     111                 :           0 :         err = vhd_read_bitmap(vhd, block, &map);
     112         [ #  # ]:           0 :         if (err)
     113                 :           0 :                 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                 :           0 :                         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                 :           0 :                         goto done;
     144                 :             : 
     145                 :           0 :                 coalesced_size += (int64_t)secs;
     146                 :           0 :                 i += (uint32_t)secs;
     147                 :             :         }
     148                 :             : 
     149                 :             :         err = 0;
     150                 :             : 
     151                 :           0 : 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                 :           0 :         int i;
     174                 :           0 :         int64_t err;
     175                 :           0 :         int64_t coalesced_size = 0;
     176                 :             : 
     177                 :           0 :         err = vhd_get_bat(from);
     178         [ #  # ]:           0 :         if (err)
     179                 :           0 :                 goto out;
     180                 :             : 
     181         [ #  # ]:           0 :         if (vhd_has_batmap(from)) {
     182                 :           0 :                 err = vhd_get_batmap(from);
     183         [ #  # ]:           0 :                 if (err)
     184                 :           0 :                         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                 :           0 :                         goto out;
     196                 :             : 
     197                 :           0 :                 coalesced_size += err;
     198                 :             :         }
     199                 :             : 
     200                 :           0 :         err = 0;
     201                 :             : 
     202         [ #  # ]:           0 :         if (progress)
     203                 :           0 :                 printf("\r100.00%%\n");
     204                 :             : 
     205                 :           0 : out:
     206         [ #  # ]:           0 :         if (err < 0)
     207                 :           0 :                 return err;
     208                 :             : 
     209                 :             :         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                 :           0 :         char *pname;
     224                 :           0 :         int64_t err;
     225                 :           0 :         int parent_fd;
     226                 :           0 :         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                 :           0 :                 printf("error opening %s: %" PRId64 "\n", name, err);
     234                 :           0 :                 return err;
     235                 :             :         }
     236                 :             : 
     237         [ #  # ]:           0 :         if (vhd.footer.type != HD_TYPE_DIFF) {
     238                 :           0 :                 printf("coalescing of non-differencing disks is not supported\n");
     239                 :           0 :                 vhd_close(&vhd);
     240                 :           0 :                 return -EINVAL;
     241                 :             :         }
     242                 :             : 
     243                 :           0 :         err = vhd_parent_locator_get(&vhd, &pname);
     244         [ #  # ]:           0 :         if (err) {
     245                 :           0 :                 printf("error finding %s parent: %" PRId64 "\n", name, err);
     246                 :           0 :                 vhd_close(&vhd);
     247                 :           0 :                 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                 :           0 :                         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                 :           0 :                         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                 :             :         return err;
     280                 :             : }
     281                 :             : 
     282                 :             : int
     283                 :           0 : vhd_util_coalesce(int argc, char **argv)
     284                 :             : {
     285                 :           0 :         char *name;
     286                 :           0 :         int c, progress, sparse;
     287                 :           0 :         int64_t result;
     288                 :             : 
     289                 :           0 :         name        = NULL;
     290                 :           0 :         sparse      = 0;
     291                 :           0 :         progress    = 0;
     292                 :             : 
     293         [ #  # ]:           0 :         if (!argc || !argv)
     294                 :           0 :                 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                 :           0 :                 case 'n':
     300                 :           0 :                         name = optarg;
     301                 :           0 :                         break;
     302                 :             :                 case 's':
     303                 :             :                         sparse = 1;
     304                 :             :                         break;
     305                 :           0 :                 case 'p':
     306                 :           0 :                         progress = 1;
     307                 :           0 :                         break;
     308                 :           0 :                 case 'h':
     309                 :             :                 default:
     310                 :           0 :                         goto usage;
     311                 :             :                 }
     312                 :             :         }
     313                 :             : 
     314   [ #  #  #  # ]:           0 :         if (!name || optind != argc)
     315                 :           0 :                 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                 :           0 :         printf("Coalesced %" PRId64 " sectors", result);
     326                 :           0 :         return 0;
     327                 :             : 
     328                 :           0 : usage:
     329                 :           0 :         printf("options: <-n name> "
     330                 :             :                "[-s sparse] [-p progress] "
     331                 :             :                "[-h help]\n");
     332                 :           0 :         return -EINVAL;
     333                 :             : }
        

Generated by: LCOV version 2.0-1