LCOV - code coverage report
Current view: top level - vhd/lib - vhd-util-snapshot.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 44 99 44.4 %
Date: 2025-02-07 10:09:38 Functions: 1 3 33.3 %
Branches: 26 74 35.1 %

           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 <stdio.h>
      37                 :            : #include <fcntl.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 : vhd_util_find_snapshot_target(const char *name, char **result, int *parent_raw)
      47                 :            : {
      48                 :            :         int i, err;
      49                 :            :         char *target;
      50                 :            :         vhd_context_t vhd;
      51                 :            : 
      52                 :          0 :         *parent_raw = 0;
      53                 :          0 :         *result     = NULL;
      54                 :            : 
      55                 :          0 :         target = strdup(name);
      56         [ #  # ]:          0 :         if (!target)
      57                 :          0 :                 return -ENOMEM;
      58                 :            : 
      59                 :            :         for (;;) {
      60                 :          0 :                 err = vhd_open(&vhd, target, VHD_OPEN_RDONLY);
      61         [ #  # ]:          0 :                 if (err) {
      62                 :          0 :                         free(target);
      63                 :          0 :                         return err;
      64                 :            :                 }
      65                 :            : 
      66         [ #  # ]:          0 :                 if (vhd.footer.type != HD_TYPE_DIFF)
      67                 :            :                         goto out;
      68                 :            : 
      69                 :          0 :                 err = vhd_get_bat(&vhd);
      70         [ #  # ]:          0 :                 if (err)
      71                 :            :                         goto out;
      72                 :            : 
      73         [ #  # ]:          0 :                 for (i = 0; i < vhd.bat.entries; i++)
      74         [ #  # ]:          0 :                         if (vhd.bat.bat[i] != DD_BLK_UNUSED)
      75                 :            :                                 goto out;
      76                 :            : 
      77                 :          0 :                 free(target);
      78                 :          0 :                 err = vhd_parent_locator_get(&vhd, &target);
      79         [ #  # ]:          0 :                 if (err)
      80                 :            :                         goto out;
      81                 :            : 
      82         [ #  # ]:          0 :                 if (vhd_parent_raw(&vhd)) {
      83                 :          0 :                         *parent_raw = 1;
      84                 :          0 :                         goto out;
      85                 :            :                 }
      86                 :            : 
      87                 :          0 :                 vhd_close(&vhd);
      88                 :            :         }
      89                 :            : 
      90                 :            : out:
      91                 :          0 :         vhd_close(&vhd);
      92         [ #  # ]:          0 :         if (err)
      93                 :          0 :                 free(target);
      94                 :            :         else
      95                 :          0 :                 *result = target;
      96                 :            : 
      97                 :          0 :         return err;
      98                 :            : }
      99                 :            : 
     100                 :            : static int
     101                 :          0 : vhd_util_check_depth(const char *name, int *depth)
     102                 :            : {
     103                 :            :         int err;
     104                 :            :         vhd_context_t vhd;
     105                 :            : 
     106                 :          0 :         err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
     107         [ #  # ]:          0 :         if (err)
     108                 :          0 :                 return err;
     109                 :            : 
     110                 :          0 :         err = vhd_chain_depth(&vhd, depth);
     111                 :          0 :         vhd_close(&vhd);
     112                 :            : 
     113                 :            :         return err;
     114                 :            : }
     115                 :            : 
     116                 :            : int
     117                 :          5 : vhd_util_snapshot(int argc, char **argv)
     118                 :            : {
     119                 :            :         vhd_flag_creat_t flags;
     120                 :            :         int c, err, prt_raw, limit, empty_check;
     121                 :            :         char *name, *pname, *backing;
     122                 :            :         char *ppath, __ppath[PATH_MAX];
     123                 :            :         uint64_t size, msize;
     124                 :            :         vhd_context_t vhd;
     125                 :            : 
     126                 :          5 :         name        = NULL;
     127                 :          5 :         pname       = NULL;
     128                 :          5 :         ppath       = NULL;
     129                 :          5 :         backing     = NULL;
     130                 :          5 :         size        = 0;
     131                 :          5 :         msize       = 0;
     132                 :          5 :         flags       = 0;
     133                 :          5 :         limit       = 0;
     134                 :          5 :         empty_check = 1;
     135                 :            : 
     136         [ +  - ]:          5 :         if (!argc || !argv) {
     137                 :            :                 err = -EINVAL;
     138                 :            :                 goto usage;
     139                 :            :         }
     140                 :            : 
     141                 :          5 :         optind = 0;
     142         [ +  + ]:         26 :         while ((c = getopt(argc, argv, "n:p:S:l:meh")) != -1) {
     143                 :            : 
     144   [ +  +  +  -  :         21 :                 switch (c) {
             +  -  +  - ]
     145                 :            :                 case 'n':
     146                 :          5 :                         name = optarg;
     147                 :          5 :                         break;
     148                 :            :                 case 'p':
     149                 :          5 :                         pname = optarg;
     150                 :          5 :                         break;
     151                 :            :                 case 'S':
     152                 :          5 :                         msize = strtoull(optarg, NULL, 10);
     153                 :         21 :                         break;
     154                 :            :                 case 'l':
     155                 :          0 :                         limit = strtol(optarg, NULL, 10);
     156                 :          0 :                         break;
     157                 :            :                 case 'm':
     158                 :            :                         vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
     159                 :            :                         break;
     160                 :            :                 case 'e':
     161                 :          5 :                         empty_check = 0;
     162                 :          5 :                         break;
     163                 :            :                 case 'h':
     164                 :            :                         err = 0;
     165                 :            :                         goto usage;
     166                 :            :                 default:
     167                 :          0 :                         err = -EINVAL;
     168                 :          0 :                         goto usage;
     169                 :            :                 }
     170                 :            :         }
     171                 :            : 
     172 [ +  - ][ +  - ]:          5 :         if (!name || !pname || optind != argc) {
     173                 :            :                 err = -EINVAL;
     174                 :            :                 goto usage;
     175                 :            :         }
     176                 :            : 
     177                 :          5 :         ppath = canonpath(pname, __ppath, sizeof(__ppath));
     178         [ -  + ]:          5 :         if (!ppath)
     179                 :          0 :                 return -errno;
     180                 :            : 
     181 [ +  + ][ +  - ]:          5 :         if (vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW) || !empty_check) {
     182                 :          5 :                 backing = strdup(ppath);
     183         [ +  - ]:          5 :                 if (!backing) {
     184                 :            :                         err = -ENOMEM;
     185                 :            :                         goto out;
     186                 :            :                 }
     187                 :            :         } else {
     188                 :          0 :                 err = vhd_util_find_snapshot_target(ppath, &backing, &prt_raw);
     189         [ #  # ]:          0 :                 if (err) {
     190                 :          0 :                         backing = NULL;
     191                 :          0 :                         goto out;
     192                 :            :                 }
     193                 :            : 
     194                 :            :                 /* 
     195                 :            :                  * if the sizes of the parent chain are non-uniform, we need to 
     196                 :            :                  * pick the right size: that of the supplied parent
     197                 :            :                  */
     198         [ #  # ]:          0 :                 if (strcmp(ppath, backing)) {
     199                 :          0 :                         err = vhd_open(&vhd, ppath, VHD_OPEN_RDONLY);
     200         [ #  # ]:          0 :                         if (err)
     201                 :            :                                 goto out;
     202                 :          0 :                         size = vhd.footer.curr_size;
     203                 :          0 :                         vhd_close(&vhd);
     204                 :            :                 }
     205                 :            : 
     206         [ #  # ]:          0 :                 if (prt_raw)
     207                 :          0 :                         vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
     208                 :            :         }
     209                 :            : 
     210 [ -  + ][ #  # ]:          5 :         if (limit && !vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) {
     211                 :            :                 int depth;
     212                 :            : 
     213                 :          0 :                 err = vhd_util_check_depth(backing, &depth);
     214         [ #  # ]:          0 :                 if (err)
     215                 :            :                         printf("error checking snapshot depth: %d\n", err);
     216         [ #  # ]:          0 :                 else if (depth + 1 > limit) {
     217                 :          0 :                         err = -ENOSPC;
     218                 :          0 :                         printf("snapshot depth exceeded: "
     219                 :            :                                "current depth: %d, limit: %d\n", depth, limit);
     220                 :            :                 }
     221                 :            : 
     222         [ #  # ]:          0 :                 if (err)
     223                 :            :                         goto out;
     224                 :            :         }
     225                 :            : 
     226                 :          5 :         err = vhd_snapshot(name, size, backing, msize << 20, flags);
     227         [ +  + ]:          5 :         if(err)
     228                 :            :                 goto out;
     229                 :            : 
     230         [ +  - ]:          4 :         if (!vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) {
     231                 :            :                 /* Set keyhash if it exists in parent */
     232                 :            :                 struct vhd_keyhash vhdhash;
     233                 :          4 :                 err = vhd_open(&vhd, backing, VHD_OPEN_RDONLY);
     234         [ +  + ]:          4 :                 if(err)
     235                 :            :                         goto out;
     236                 :          3 :                 err = vhd_get_keyhash(&vhd, &vhdhash);
     237                 :          3 :                 vhd_close(&vhd);
     238         [ +  + ]:          3 :                 if(err)
     239                 :            :                         goto out;
     240         [ +  - ]:          2 :                 if (vhdhash.cookie == 1){
     241                 :          2 :                         err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
     242         [ +  + ]:          2 :                         if(err)
     243                 :            :                                 goto out;
     244                 :          1 :                         err = vhd_set_keyhash(&vhd, &vhdhash);
     245                 :          4 :                         vhd_close(&vhd);
     246                 :            :                 }
     247                 :            :         }
     248                 :            : 
     249                 :            : out:
     250                 :          5 :         free(backing);
     251                 :            : 
     252                 :          5 :         return err;
     253                 :            : 
     254                 :            : usage:
     255                 :            :         printf("options: <-n name> <-p parent name> [-l snapshot depth limit]"
     256                 :            :                " [-m parent_is_raw] [-S size (MB) for metadata preallocation "
     257                 :            :                "(see vhd-util resize)] [-e link to supplied parent name even "
     258                 :            :                "if it's empty] [-h help]\n");
     259                 :            :         return err;
     260                 :            : }

Generated by: LCOV version 1.13