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 : : }
|