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 : : /*
32 : : * Before updating a VHD file, we create a journal consisting of:
33 : : * - all data at the beginning of the file, up to and including the BAT
34 : : * - each allocated bitmap (existing at the same offset in the journal as
35 : : * its corresponding bitmap in the original file)
36 : : * Updates are performed in place by writing appropriately
37 : : * transformed versions of journaled bitmaps to the original file.
38 : : */
39 : :
40 : : #ifdef HAVE_CONFIG_H
41 : : #include "config.h"
42 : : #endif
43 : :
44 : : #include <stdio.h>
45 : : #include <errno.h>
46 : : #include <fcntl.h>
47 : : #include <stdlib.h>
48 : : #include <unistd.h>
49 : : #include <endian.h>
50 : : #include <byteswap.h>
51 : :
52 : : #include "libvhd.h"
53 : : #include "libvhd-journal.h"
54 : :
55 : : static void
56 : 0 : usage(void)
57 : : {
58 : : printf("usage: vhd-update <-n name> [-j existing journal] [-h]\n");
59 : 0 : exit(EINVAL);
60 : : }
61 : :
62 : : /*
63 : : * update vhd creator version to reflect its new bitmap ordering
64 : : */
65 : : static inline int
66 : : update_creator_version(vhd_journal_t *journal)
67 : : {
68 : 0 : journal->vhd.footer.crtr_ver = VHD_VERSION(1, 1);
69 : 0 : return vhd_write_footer(&journal->vhd, &journal->vhd.footer);
70 : : }
71 : :
72 : : static int
73 : 0 : journal_bitmaps(vhd_journal_t *journal)
74 : : {
75 : : int i, err;
76 : :
77 : 0 : for (i = 0; i < journal->vhd.bat.entries; i++) {
78 : 0 : err = vhd_journal_add_block(journal, i, VHD_JOURNAL_METADATA);
79 : 0 : if (err)
80 : : return err;
81 : : }
82 : :
83 : : return 0;
84 : : }
85 : :
86 : : /*
87 : : * older VHD bitmaps were little endian
88 : : * and bits within a word were set from right to left
89 : : */
90 : : static inline int
91 : : old_test_bit(int nr, volatile void * addr)
92 : : {
93 : 0 : return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
94 : : (nr % (sizeof(unsigned long)*8))) & 1;
95 : : }
96 : :
97 : : /*
98 : : * new VHD bitmaps are big endian
99 : : * and bits within a word are set from left to right
100 : : */
101 : : #define BIT_MASK 0x80
102 : : static inline void
103 : : new_set_bit (int nr, volatile char *addr)
104 : : {
105 : 0 : addr[nr >> 3] |= (BIT_MASK >> (nr & 7));
106 : : }
107 : :
108 : : static void
109 : 0 : convert_bitmap(char *in, char *out, int bytes)
110 : : {
111 : : int i;
112 : :
113 : 0 : memset(out, 0, bytes);
114 : :
115 : 0 : for (i = 0; i < bytes << 3; i++)
116 : 0 : if (old_test_bit(i, (void *)in))
117 : : new_set_bit(i, out);
118 : 0 : }
119 : :
120 : : static int
121 : 0 : update_vhd(vhd_journal_t *journal, int rollback)
122 : : {
123 : : int i, err;
124 : : size_t size;
125 : : char *buf;
126 : : void *converted;
127 : :
128 : 0 : buf = NULL;
129 : 0 : converted = NULL;
130 : :
131 : 0 : size = vhd_bytes_padded(journal->vhd.spb / 8);
132 : 0 : err = posix_memalign(&converted, 512, size);
133 : 0 : if (err) {
134 : 0 : converted = NULL;
135 : 0 : goto out;
136 : : }
137 : :
138 : 0 : for (i = 0; i < journal->vhd.bat.entries; i++) {
139 : 0 : if (journal->vhd.bat.bat[i] == DD_BLK_UNUSED)
140 : 0 : continue;
141 : :
142 : 0 : err = vhd_read_bitmap(&journal->vhd, i, &buf);
143 : 0 : if (err)
144 : : goto out;
145 : :
146 : 0 : if (rollback)
147 : 0 : memcpy(converted, buf, size);
148 : : else
149 : 0 : convert_bitmap(buf, converted, size);
150 : :
151 : 0 : free(buf);
152 : :
153 : 0 : err = vhd_write_bitmap(&journal->vhd, i, converted);
154 : 0 : if (err)
155 : : goto out;
156 : : }
157 : :
158 : : err = 0;
159 : : out:
160 : 0 : free(converted);
161 : 0 : return err;
162 : : }
163 : :
164 : : static int
165 : 0 : open_journal(vhd_journal_t *journal, const char *file, const char *jfile)
166 : : {
167 : : int err;
168 : :
169 : 0 : err = vhd_journal_create(journal, file, jfile);
170 : 0 : if (err) {
171 : : printf("error creating journal for %s: %d\n", file, err);
172 : 0 : return err;
173 : : }
174 : :
175 : : return 0;
176 : : }
177 : :
178 : : static int
179 : 0 : close_journal(vhd_journal_t *journal, int err)
180 : : {
181 : 0 : if (err)
182 : 0 : err = vhd_journal_revert(journal);
183 : : else
184 : 0 : err = vhd_journal_commit(journal);
185 : :
186 : 0 : if (err)
187 : 0 : return vhd_journal_close(journal);
188 : : else
189 : 0 : return vhd_journal_remove(journal);
190 : : }
191 : :
192 : : int
193 : 0 : main(int argc, char **argv)
194 : : {
195 : : char *file, *jfile;
196 : : int c, err, rollback;
197 : : vhd_journal_t journal;
198 : :
199 : 0 : file = NULL;
200 : 0 : jfile = NULL;
201 : 0 : rollback = 0;
202 : :
203 : 0 : while ((c = getopt(argc, argv, "n:j:rh")) != -1) {
204 : 0 : switch(c) {
205 : : case 'n':
206 : 0 : file = optarg;
207 : 0 : break;
208 : : case 'j':
209 : 0 : jfile = optarg;
210 : 0 : err = access(jfile, R_OK);
211 : 0 : if (err == -1) {
212 : : printf("invalid journal arg %s\n", jfile);
213 : 0 : return -errno;
214 : : }
215 : : break;
216 : : case 'r':
217 : : /* add a rollback option for debugging which
218 : : * pushes journalled bitmaps to original file
219 : : * without transforming them */
220 : : rollback = 1;
221 : : break;
222 : : default:
223 : 0 : usage();
224 : : }
225 : : }
226 : :
227 : 0 : if (!file)
228 : 0 : usage();
229 : :
230 : 0 : if (rollback && !jfile) {
231 : : printf("rollback requires a journal argument\n");
232 : 0 : usage();
233 : : }
234 : :
235 : 0 : err = open_journal(&journal, file, jfile);
236 : 0 : if (err)
237 : : return err;
238 : :
239 : 0 : if (!vhd_creator_tapdisk(&journal.vhd) ||
240 : 0 : journal.vhd.footer.crtr_ver != VHD_VERSION(0, 1) ||
241 : 0 : journal.vhd.footer.type == HD_TYPE_FIXED) {
242 : : err = 0;
243 : : goto out;
244 : : }
245 : :
246 : 0 : err = journal_bitmaps(&journal);
247 : 0 : if (err) {
248 : : /* no changes to vhd file yet,
249 : : * so close the journal and bail */
250 : 0 : vhd_journal_close(&journal);
251 : : return err;
252 : : }
253 : :
254 : 0 : err = update_vhd(&journal, rollback);
255 : 0 : if (err) {
256 : : printf("update failed: %d; saving journal\n", err);
257 : : goto out;
258 : : }
259 : :
260 : 0 : err = update_creator_version(&journal);
261 : 0 : if (err) {
262 : : printf("failed to udpate creator version: %d\n", err);
263 : : goto out;
264 : : }
265 : :
266 : : err = 0;
267 : :
268 : : out:
269 : 0 : err = close_journal(&journal, err);
270 : : return err;
271 : : }
|