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

Generated by: LCOV version 1.13