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 <stdio.h>
36 : : #include <errno.h>
37 : : #include <fcntl.h>
38 : : #include <stdlib.h>
39 : : #include <unistd.h>
40 : : #include <string.h>
41 : :
42 : : #include "atomicio.h"
43 : : #include "libvhd-journal.h"
44 : :
45 : : #define VHD_JOURNAL_ENTRY_TYPE_FOOTER_P 1
46 : : #define VHD_JOURNAL_ENTRY_TYPE_FOOTER_C 2
47 : : #define VHD_JOURNAL_ENTRY_TYPE_HEADER 3
48 : : #define VHD_JOURNAL_ENTRY_TYPE_LOCATOR 4
49 : : #define VHD_JOURNAL_ENTRY_TYPE_BAT 5
50 : : #define VHD_JOURNAL_ENTRY_TYPE_BATMAP_H 6
51 : : #define VHD_JOURNAL_ENTRY_TYPE_BATMAP_M 7
52 : : #define VHD_JOURNAL_ENTRY_TYPE_DATA 8
53 : :
54 : : typedef struct vhd_journal_entry {
55 : : uint64_t cookie;
56 : : uint32_t type;
57 : : uint32_t size;
58 : : uint64_t offset;
59 : : uint32_t checksum;
60 : : } vhd_journal_entry_t;
61 : :
62 : : static inline int
63 : 0 : vhd_journal_seek(vhd_journal_t *j, off64_t offset, int whence)
64 : : {
65 : : off64_t off;
66 : :
67 : 0 : off = lseek64(j->jfd, offset, whence);
68 [ # # ]: 0 : if (off == (off64_t)-1)
69 : 0 : return -errno;
70 : :
71 : : return 0;
72 : : }
73 : :
74 : : static inline off64_t
75 : 0 : vhd_journal_position(vhd_journal_t *j)
76 : : {
77 : 0 : return lseek64(j->jfd, 0, SEEK_CUR);
78 : : }
79 : :
80 : : static inline int
81 : 0 : vhd_journal_read(vhd_journal_t *j, void *buf, size_t size)
82 : : {
83 : : ssize_t ret;
84 : :
85 : 0 : errno = 0;
86 : :
87 : 0 : ret = atomicio(read, j->jfd, buf, size);
88 [ # # ]: 0 : if (ret != size)
89 [ # # ]: 0 : return (errno ? -errno : -EIO);
90 : :
91 : : return 0;
92 : : }
93 : :
94 : : static inline int
95 : 0 : vhd_journal_write(vhd_journal_t *j, void *buf, size_t size)
96 : : {
97 : : ssize_t ret;
98 : :
99 : 0 : errno = 0;
100 : :
101 : 0 : ret = atomicio(vwrite, j->jfd, buf, size);
102 [ # # ]: 0 : if (ret != size)
103 [ # # ]: 0 : return (errno ? -errno : -EIO);
104 : :
105 : : return 0;
106 : : }
107 : :
108 : : static inline int
109 : 0 : vhd_journal_truncate(vhd_journal_t *j, off64_t length)
110 : : {
111 : : int err;
112 : :
113 : 0 : err = ftruncate(j->jfd, length);
114 [ # # ]: 0 : if (err == -1)
115 : 0 : return -errno;
116 : :
117 : : return 0;
118 : : }
119 : :
120 : : static inline int
121 : 0 : vhd_journal_sync(vhd_journal_t *j)
122 : : {
123 : : int err;
124 : :
125 : 0 : err = fdatasync(j->jfd);
126 [ # # ]: 0 : if (err)
127 : 0 : return -errno;
128 : :
129 : : return 0;
130 : : }
131 : :
132 : : static inline void
133 : : vhd_journal_header_in(vhd_journal_header_t *header)
134 : : {
135 : 0 : BE64_IN(&header->vhd_footer_offset);
136 : 0 : BE32_IN(&header->journal_data_entries);
137 : 0 : BE32_IN(&header->journal_metadata_entries);
138 : 0 : BE64_IN(&header->journal_data_offset);
139 : 0 : BE64_IN(&header->journal_metadata_offset);
140 : : }
141 : :
142 : : static inline void
143 : : vhd_journal_header_out(vhd_journal_header_t *header)
144 : : {
145 : 0 : BE64_OUT(&header->vhd_footer_offset);
146 : 0 : BE32_OUT(&header->journal_data_entries);
147 : 0 : BE32_OUT(&header->journal_metadata_entries);
148 : 0 : BE64_OUT(&header->journal_data_offset);
149 : 0 : BE64_OUT(&header->journal_metadata_offset);
150 : : }
151 : :
152 : : static int
153 : 0 : vhd_journal_validate_header(vhd_journal_t *j, vhd_journal_header_t *header)
154 : : {
155 : : int err;
156 : : off64_t eof;
157 : :
158 [ # # ]: 0 : if (memcmp(header->cookie,
159 : : VHD_JOURNAL_HEADER_COOKIE, sizeof(header->cookie)))
160 : : return -EINVAL;
161 : :
162 : 0 : err = vhd_journal_seek(j, j->header.journal_eof, SEEK_SET);
163 [ # # ]: 0 : if (err)
164 : : return err;
165 : :
166 : 0 : eof = vhd_journal_position(j);
167 [ # # ]: 0 : if (eof == (off64_t)-1)
168 : 0 : return -errno;
169 : :
170 [ # # ]: 0 : if (j->header.journal_data_offset > j->header.journal_eof)
171 : : return -EINVAL;
172 : :
173 [ # # ]: 0 : if (j->header.journal_metadata_offset > j->header.journal_eof)
174 : : return -EINVAL;
175 : :
176 : 0 : return 0;
177 : : }
178 : :
179 : : static int
180 : 0 : vhd_journal_read_journal_header(vhd_journal_t *j, vhd_journal_header_t *header)
181 : : {
182 : : int err;
183 : : size_t size;
184 : :
185 : 0 : size = sizeof(vhd_journal_header_t);
186 : 0 : err = vhd_journal_seek(j, 0, SEEK_SET);
187 [ # # ]: 0 : if (err)
188 : : return err;
189 : :
190 : 0 : err = vhd_journal_read(j, header, size);
191 [ # # ]: 0 : if (err)
192 : : return err;
193 : :
194 : : vhd_journal_header_in(header);
195 : :
196 : 0 : return vhd_journal_validate_header(j, header);
197 : : }
198 : :
199 : : static int
200 : 0 : vhd_journal_write_header(vhd_journal_t *j, vhd_journal_header_t *header)
201 : : {
202 : : int err;
203 : : size_t size;
204 : : vhd_journal_header_t h;
205 : :
206 : : memcpy(&h, header, sizeof(vhd_journal_header_t));
207 : :
208 : 0 : err = vhd_journal_validate_header(j, &h);
209 [ # # ]: 0 : if (err)
210 : 0 : return err;
211 : :
212 : : vhd_journal_header_out(&h);
213 : 0 : size = sizeof(vhd_journal_header_t);
214 : :
215 : 0 : err = vhd_journal_seek(j, 0, SEEK_SET);
216 [ # # ]: 0 : if (err)
217 : : return err;
218 : :
219 : 0 : err = vhd_journal_write(j, &h, size);
220 [ # # ]: 0 : if (err)
221 : 0 : return err;
222 : :
223 : : return 0;
224 : : }
225 : :
226 : : static int
227 : 0 : vhd_journal_add_journal_header(vhd_journal_t *j)
228 : : {
229 : : int err;
230 : : off64_t off;
231 : : vhd_context_t *vhd;
232 : :
233 : 0 : vhd = &j->vhd;
234 : 0 : memset(&j->header, 0, sizeof(vhd_journal_header_t));
235 : :
236 : 0 : err = vhd_seek(vhd, 0, SEEK_END);
237 [ # # ]: 0 : if (err)
238 : : return err;
239 : :
240 : 0 : off = vhd_position(vhd);
241 [ # # ]: 0 : if (off == (off64_t)-1)
242 : 0 : return -errno;
243 : :
244 : 0 : err = vhd_get_footer(vhd);
245 [ # # ]: 0 : if (err)
246 : : return err;
247 : :
248 : 0 : uuid_copy(j->header.uuid, vhd->footer.uuid);
249 : 0 : memcpy(j->header.cookie,
250 : : VHD_JOURNAL_HEADER_COOKIE, sizeof(j->header.cookie));
251 : 0 : j->header.vhd_footer_offset = off - sizeof(vhd_footer_t);
252 : 0 : j->header.journal_eof = sizeof(vhd_journal_header_t);
253 : :
254 : 0 : return vhd_journal_write_header(j, &j->header);
255 : : }
256 : :
257 : : static void
258 : : vhd_journal_entry_in(vhd_journal_entry_t *entry)
259 : : {
260 : 0 : BE32_IN(&entry->type);
261 : 0 : BE32_IN(&entry->size);
262 : 0 : BE64_IN(&entry->offset);
263 : 0 : BE64_IN(&entry->cookie);
264 : 0 : BE32_IN(&entry->checksum);
265 : : }
266 : :
267 : : static void
268 : : vhd_journal_entry_out(vhd_journal_entry_t *entry)
269 : : {
270 : 0 : BE32_OUT(&entry->type);
271 : 0 : BE32_OUT(&entry->size);
272 : 0 : BE64_OUT(&entry->offset);
273 : 0 : BE64_OUT(&entry->cookie);
274 : 0 : BE32_OUT(&entry->checksum);
275 : : }
276 : :
277 : : static uint32_t
278 : : vhd_journal_checksum_entry(vhd_journal_entry_t *entry, char *buf, size_t size)
279 : : {
280 : : int i;
281 : : unsigned char *blob;
282 : : uint32_t checksum, tmp;
283 : :
284 : 0 : checksum = 0;
285 : 0 : tmp = entry->checksum;
286 : 0 : entry->checksum = 0;
287 : :
288 : 0 : blob = (unsigned char *)entry;
289 [ # # ][ # # ]: 0 : for (i = 0; i < sizeof(vhd_journal_entry_t); i++)
290 : 0 : checksum += blob[i];
291 : :
292 : : blob = (unsigned char *)buf;
293 [ # # ][ # # ]: 0 : for (i = 0; i < size; i++)
294 : 0 : checksum += blob[i];
295 : :
296 : 0 : entry->checksum = tmp;
297 : 0 : return ~checksum;
298 : : }
299 : :
300 : : static int
301 : 0 : vhd_journal_validate_entry(vhd_journal_entry_t *entry)
302 : : {
303 [ # # ][ # # ]: 0 : if (entry->size == 0)
304 : : return -EINVAL;
305 : :
306 [ # # ][ # # ]: 0 : if (entry->size & (VHD_SECTOR_SIZE - 1))
307 : : return -EINVAL;
308 : :
309 [ # # ][ # # ]: 0 : if (entry->cookie != VHD_JOURNAL_ENTRY_COOKIE)
310 : : return -EINVAL;
311 : :
312 : 0 : return 0;
313 : : }
314 : :
315 : : static int
316 : 0 : vhd_journal_read_entry(vhd_journal_t *j, vhd_journal_entry_t *entry)
317 : : {
318 : : int err;
319 : :
320 : 0 : err = vhd_journal_read(j, entry, sizeof(vhd_journal_entry_t));
321 [ # # ]: 0 : if (err)
322 : : return err;
323 : :
324 : : vhd_journal_entry_in(entry);
325 : 0 : return vhd_journal_validate_entry(entry);
326 : : }
327 : :
328 : : static int
329 : 0 : vhd_journal_write_entry(vhd_journal_t *j, vhd_journal_entry_t *entry)
330 : : {
331 : : int err;
332 : : vhd_journal_entry_t e;
333 : :
334 : 0 : err = vhd_journal_validate_entry(entry);
335 [ # # ]: 0 : if (err)
336 : 0 : return err;
337 : :
338 : : memcpy(&e, entry, sizeof(vhd_journal_entry_t));
339 : : vhd_journal_entry_out(&e);
340 : :
341 : 0 : err = vhd_journal_write(j, &e, sizeof(vhd_journal_entry_t));
342 [ # # ]: 0 : if (err)
343 : 0 : return err;
344 : :
345 : : return 0;
346 : : }
347 : :
348 : : static int
349 : 0 : vhd_journal_validate_entry_data(vhd_journal_entry_t *entry, char *buf)
350 : : {
351 : : int err;
352 : : uint32_t checksum;
353 : :
354 : 0 : err = 0;
355 : 0 : checksum = vhd_journal_checksum_entry(entry, buf, entry->size);
356 : :
357 [ # # ]: 0 : if (checksum != entry->checksum)
358 : : return -EINVAL;
359 : :
360 : 0 : return err;
361 : : }
362 : :
363 : : static int
364 : 0 : vhd_journal_update(vhd_journal_t *j, off64_t offset,
365 : : char *buf, size_t size, uint32_t type)
366 : : {
367 : : int err;
368 : : uint64_t *off, off_bak;
369 : : uint32_t *entries;
370 : : vhd_journal_entry_t entry;
371 : :
372 : 0 : entry.type = type;
373 : 0 : entry.size = size;
374 : 0 : entry.offset = offset;
375 : 0 : entry.cookie = VHD_JOURNAL_ENTRY_COOKIE;
376 : 0 : entry.checksum = vhd_journal_checksum_entry(&entry, buf, size);
377 : :
378 : 0 : err = vhd_journal_seek(j, j->header.journal_eof, SEEK_SET);
379 [ # # ]: 0 : if (err)
380 : 0 : return err;
381 : :
382 : 0 : err = vhd_journal_write_entry(j, &entry);
383 [ # # ]: 0 : if (err)
384 : : goto fail;
385 : :
386 : 0 : err = vhd_journal_write(j, buf, size);
387 [ # # ]: 0 : if (err)
388 : : goto fail;
389 : :
390 [ # # ]: 0 : if (type == VHD_JOURNAL_ENTRY_TYPE_DATA) {
391 : 0 : off = &j->header.journal_data_offset;
392 : 0 : entries = &j->header.journal_data_entries;
393 : : } else {
394 : 0 : off = &j->header.journal_metadata_offset;
395 : 0 : entries = &j->header.journal_metadata_entries;
396 : : }
397 : :
398 : 0 : off_bak = *off;
399 [ # # ]: 0 : if (!(*entries)++)
400 : 0 : *off = j->header.journal_eof;
401 : 0 : j->header.journal_eof += (size + sizeof(vhd_journal_entry_t));
402 : :
403 : 0 : err = vhd_journal_write_header(j, &j->header);
404 [ # # ]: 0 : if (err) {
405 [ # # ]: 0 : if (!--(*entries))
406 : 0 : *off = off_bak;
407 : 0 : j->header.journal_eof -= (size + sizeof(vhd_journal_entry_t));
408 : 0 : goto fail;
409 : : }
410 : :
411 : : return 0;
412 : :
413 : : fail:
414 [ # # ]: 0 : if (!j->is_block)
415 : 0 : vhd_journal_truncate(j, j->header.journal_eof);
416 : 0 : return err;
417 : : }
418 : :
419 : : static int
420 : 0 : vhd_journal_add_footer(vhd_journal_t *j)
421 : : {
422 : : int err;
423 : : off64_t off;
424 : 0 : vhd_context_t *vhd;
425 : : vhd_footer_t footer;
426 : :
427 : 0 : vhd = &j->vhd;
428 : :
429 : 0 : err = vhd_seek(vhd, 0, SEEK_END);
430 [ # # ]: 0 : if (err)
431 : 0 : return err;
432 : :
433 : 0 : off = vhd_position(vhd);
434 [ # # ]: 0 : if (off == (off64_t)-1)
435 : 0 : return -errno;
436 : :
437 : 0 : err = vhd_read_footer_at(vhd, &footer, off - sizeof(vhd_footer_t));
438 [ # # ]: 0 : if (err)
439 : : return err;
440 : :
441 : 0 : vhd_footer_out(&footer);
442 : 0 : err = vhd_journal_update(j, off - sizeof(vhd_footer_t),
443 : : (char *)&footer,
444 : : sizeof(vhd_footer_t),
445 : : VHD_JOURNAL_ENTRY_TYPE_FOOTER_P);
446 [ # # ]: 0 : if (err)
447 : : return err;
448 : :
449 [ # # ]: 0 : if (!vhd_type_dynamic(vhd))
450 : : return 0;
451 : :
452 : 0 : err = vhd_read_footer_at(vhd, &footer, 0);
453 [ # # ]: 0 : if (err)
454 : : return err;
455 : :
456 : 0 : vhd_footer_out(&footer);
457 : 0 : err = vhd_journal_update(j, 0,
458 : : (char *)&footer,
459 : : sizeof(vhd_footer_t),
460 : : VHD_JOURNAL_ENTRY_TYPE_FOOTER_C);
461 : :
462 : : return err;
463 : : }
464 : :
465 : : static int
466 : 0 : vhd_journal_add_header(vhd_journal_t *j)
467 : : {
468 : : int err;
469 : : off64_t off;
470 : : vhd_context_t *vhd;
471 : : vhd_header_t header;
472 : :
473 : 0 : vhd = &j->vhd;
474 : :
475 : 0 : err = vhd_read_header(vhd, &header);
476 [ # # ]: 0 : if (err)
477 : 0 : return err;
478 : :
479 : 0 : off = vhd->footer.data_offset;
480 : :
481 : 0 : vhd_header_out(&header);
482 : 0 : err = vhd_journal_update(j, off,
483 : : (char *)&header,
484 : : sizeof(vhd_header_t),
485 : : VHD_JOURNAL_ENTRY_TYPE_HEADER);
486 : :
487 : : return err;
488 : : }
489 : :
490 : : static int
491 : 0 : vhd_journal_add_locators(vhd_journal_t *j)
492 : : {
493 : : int i, n, err;
494 : : vhd_context_t *vhd;
495 : :
496 : 0 : vhd = &j->vhd;
497 : :
498 : 0 : err = vhd_get_header(vhd);
499 [ # # ]: 0 : if (err)
500 : : return err;
501 : :
502 : : n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t);
503 [ # # ]: 0 : for (i = 0; i < n; i++) {
504 : : void *buf;
505 : : off64_t off;
506 : : size_t size;
507 : 0 : vhd_parent_locator_t *loc;
508 : :
509 : 0 : loc = vhd->header.loc + i;
510 : 0 : err = vhd_validate_platform_code(loc->code);
511 [ # # ]: 0 : if (err)
512 : 0 : return err;
513 : :
514 [ # # ]: 0 : if (loc->code == PLAT_CODE_NONE)
515 : 0 : continue;
516 : :
517 : 0 : off = loc->data_offset;
518 : 0 : size = vhd_parent_locator_size(loc);
519 : :
520 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
521 [ # # ]: 0 : if (err)
522 : 0 : return -err;
523 : :
524 : 0 : err = vhd_seek(vhd, off, SEEK_SET);
525 [ # # ]: 0 : if (err)
526 : : goto end;
527 : :
528 : 0 : err = vhd_read(vhd, buf, size);
529 [ # # ]: 0 : if (err)
530 : : goto end;
531 : :
532 : 0 : err = vhd_journal_update(j, off, buf, size,
533 : : VHD_JOURNAL_ENTRY_TYPE_LOCATOR);
534 [ # # ]: 0 : if (err)
535 : : goto end;
536 : :
537 : 0 : err = 0;
538 : :
539 : : end:
540 : 0 : free(buf);
541 [ # # ]: 0 : if (err)
542 : : break;
543 : : }
544 : :
545 : 0 : return err;
546 : : }
547 : :
548 : : static int
549 : 0 : vhd_journal_add_bat(vhd_journal_t *j)
550 : : {
551 : : int err;
552 : : off64_t off;
553 : : size_t size;
554 : : vhd_bat_t bat;
555 : : vhd_context_t *vhd;
556 : :
557 : 0 : vhd = &j->vhd;
558 : :
559 : 0 : err = vhd_get_header(vhd);
560 [ # # ]: 0 : if (err)
561 : 0 : return err;
562 : :
563 : 0 : err = vhd_read_bat(vhd, &bat);
564 [ # # ]: 0 : if (err)
565 : : return err;
566 : :
567 : 0 : off = vhd->header.table_offset;
568 : 0 : size = vhd_bytes_padded(bat.entries * sizeof(uint32_t));
569 : :
570 : 0 : vhd_bat_out(&bat);
571 : 0 : err = vhd_journal_update(j, off, (char *)bat.bat, size,
572 : : VHD_JOURNAL_ENTRY_TYPE_BAT);
573 : :
574 : 0 : free(bat.bat);
575 : 0 : return err;
576 : : }
577 : :
578 : : static int
579 : 0 : vhd_journal_add_batmap(vhd_journal_t *j)
580 : : {
581 : : int err;
582 : : off64_t off;
583 : : size_t size;
584 : : vhd_context_t *vhd;
585 : : vhd_batmap_t batmap;
586 : :
587 : 0 : vhd = &j->vhd;
588 : :
589 : 0 : err = vhd_batmap_header_offset(vhd, &off);
590 [ # # ]: 0 : if (err)
591 : 0 : return err;
592 : :
593 : 0 : err = vhd_read_batmap(vhd, &batmap);
594 [ # # ]: 0 : if (err)
595 : : return err;
596 : :
597 : 0 : size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr));
598 : :
599 : 0 : vhd_batmap_header_out(&batmap);
600 : 0 : err = vhd_journal_update(j, off, (char *)&batmap.header, size,
601 : : VHD_JOURNAL_ENTRY_TYPE_BATMAP_H);
602 [ # # ]: 0 : if (err)
603 : : goto out;
604 : :
605 : 0 : vhd_batmap_header_in(&batmap);
606 : 0 : off = batmap.header.batmap_offset;
607 : 0 : size = vhd_sectors_to_bytes(batmap.header.batmap_size);
608 : :
609 : 0 : err = vhd_journal_update(j, off, batmap.map, size,
610 : : VHD_JOURNAL_ENTRY_TYPE_BATMAP_M);
611 : :
612 : : out:
613 : 0 : free(batmap.map);
614 : 0 : return err;
615 : : }
616 : :
617 : : static int
618 : 0 : vhd_journal_add_metadata(vhd_journal_t *j)
619 : : {
620 : : int err;
621 : 0 : vhd_context_t *vhd;
622 : :
623 : 0 : vhd = &j->vhd;
624 : :
625 : 0 : err = vhd_journal_add_footer(j);
626 [ # # ]: 0 : if (err)
627 : : return err;
628 : :
629 [ # # ]: 0 : if (!vhd_type_dynamic(vhd))
630 : : return 0;
631 : :
632 : 0 : err = vhd_journal_add_header(j);
633 [ # # ]: 0 : if (err)
634 : : return err;
635 : :
636 : 0 : err = vhd_journal_add_locators(j);
637 [ # # ]: 0 : if (err)
638 : : return err;
639 : :
640 : 0 : err = vhd_journal_add_bat(j);
641 [ # # ]: 0 : if (err)
642 : : return err;
643 : :
644 [ # # ]: 0 : if (vhd_has_batmap(vhd)) {
645 : 0 : err = vhd_journal_add_batmap(j);
646 [ # # ]: 0 : if (err)
647 : : return err;
648 : : }
649 : :
650 : 0 : j->header.journal_data_offset = j->header.journal_eof;
651 : 0 : return vhd_journal_write_header(j, &j->header);
652 : : }
653 : :
654 : : static int
655 : 0 : __vhd_journal_read_footer(vhd_journal_t *j,
656 : : vhd_footer_t *footer, uint32_t type)
657 : : {
658 : : int err;
659 : : vhd_journal_entry_t entry;
660 : :
661 : 0 : err = vhd_journal_read_entry(j, &entry);
662 [ # # ]: 0 : if (err)
663 : 0 : return err;
664 : :
665 [ # # ]: 0 : if (entry.type != type)
666 : : return -EINVAL;
667 : :
668 [ # # ]: 0 : if (entry.size != sizeof(vhd_footer_t))
669 : : return -EINVAL;
670 : :
671 : 0 : err = vhd_journal_read(j, footer, entry.size);
672 [ # # ]: 0 : if (err)
673 : : return err;
674 : :
675 : 0 : vhd_footer_in(footer);
676 : 0 : return vhd_validate_footer(footer);
677 : : }
678 : :
679 : : static int
680 : : vhd_journal_read_footer(vhd_journal_t *j, vhd_footer_t *footer)
681 : : {
682 : 0 : return __vhd_journal_read_footer(j, footer,
683 : : VHD_JOURNAL_ENTRY_TYPE_FOOTER_P);
684 : : }
685 : :
686 : : static int
687 : : vhd_journal_read_footer_copy(vhd_journal_t *j, vhd_footer_t *footer)
688 : : {
689 : 0 : return __vhd_journal_read_footer(j, footer,
690 : : VHD_JOURNAL_ENTRY_TYPE_FOOTER_C);
691 : : }
692 : :
693 : : static int
694 : 0 : vhd_journal_read_header(vhd_journal_t *j, vhd_header_t *header)
695 : : {
696 : : int err;
697 : : vhd_journal_entry_t entry;
698 : :
699 : 0 : err = vhd_journal_read_entry(j, &entry);
700 [ # # ]: 0 : if (err)
701 : 0 : return err;
702 : :
703 [ # # ]: 0 : if (entry.type != VHD_JOURNAL_ENTRY_TYPE_HEADER)
704 : : return -EINVAL;
705 : :
706 [ # # ]: 0 : if (entry.size != sizeof(vhd_header_t))
707 : : return -EINVAL;
708 : :
709 : 0 : err = vhd_journal_read(j, header, entry.size);
710 [ # # ]: 0 : if (err)
711 : : return err;
712 : :
713 : 0 : vhd_header_in(header);
714 : 0 : return vhd_validate_header(header);
715 : : }
716 : :
717 : : static int
718 : 0 : vhd_journal_read_locators(vhd_journal_t *j, char ***locators, int *locs)
719 : : {
720 : : int err, n, _locs;
721 : : char **_locators;
722 : 0 : void *buf = NULL;
723 : : off_t pos;
724 : : vhd_journal_entry_t entry;
725 : :
726 : 0 : _locs = 0;
727 : 0 : *locs = 0;
728 : 0 : *locators = NULL;
729 : :
730 : 0 : n = sizeof(j->vhd.header.loc) / sizeof(vhd_parent_locator_t);
731 : 0 : _locators = calloc(n, sizeof(char *));
732 [ # # ]: 0 : if (!_locators)
733 : 0 : return -ENOMEM;
734 : :
735 : : for (;;) {
736 : 0 : pos = vhd_journal_position(j);
737 [ # # ]: 0 : if (pos == (off64_t)-1) {
738 : 0 : err = -errno;
739 : 0 : goto fail;
740 : : }
741 : :
742 : 0 : err = vhd_journal_read_entry(j, &entry);
743 [ # # ]: 0 : if (err)
744 : : goto fail;
745 : :
746 [ # # ]: 0 : if (entry.type != VHD_JOURNAL_ENTRY_TYPE_LOCATOR) {
747 : 0 : err = vhd_journal_seek(j, pos, SEEK_SET);
748 [ # # ]: 0 : if (err)
749 : : goto fail;
750 : : break;
751 : : }
752 : :
753 [ # # ]: 0 : if (_locs >= n) {
754 : : err = -EINVAL;
755 : : goto fail;
756 : : }
757 : :
758 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, entry.size);
759 [ # # ]: 0 : if (err) {
760 : 0 : err = -err;
761 : 0 : goto fail;
762 : : }
763 : :
764 : 0 : err = vhd_journal_read(j, buf, entry.size);
765 [ # # ]: 0 : if (err)
766 : : goto fail;
767 : :
768 : 0 : _locators[_locs++] = buf;
769 : 0 : buf = NULL;
770 : 0 : err = 0;
771 : 0 : }
772 : :
773 : :
774 : 0 : *locs = _locs;
775 : 0 : *locators = _locators;
776 : :
777 : 0 : return 0;
778 : :
779 : : fail:
780 : 0 : free(buf);
781 [ # # ]: 0 : if (_locators) {
782 [ # # ]: 0 : for (n = 0; n < _locs; n++)
783 : 0 : free(_locators[n]);
784 : 0 : free(_locators);
785 : : }
786 : 0 : return err;
787 : : }
788 : :
789 : : static int
790 : 0 : vhd_journal_read_bat(vhd_journal_t *j, vhd_bat_t *bat)
791 : : {
792 : : int err;
793 : : size_t size;
794 : : vhd_context_t *vhd;
795 : : vhd_journal_entry_t entry;
796 : : void *_bat;
797 : :
798 : 0 : vhd = &j->vhd;
799 : :
800 : 0 : size = vhd_bytes_padded(vhd->header.max_bat_size * sizeof(uint32_t));
801 : :
802 : 0 : err = vhd_journal_read_entry(j, &entry);
803 [ # # ]: 0 : if (err)
804 : 0 : return err;
805 : :
806 [ # # ]: 0 : if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BAT)
807 : : return -EINVAL;
808 : :
809 [ # # ]: 0 : if (entry.size != size)
810 : : return -EINVAL;
811 : :
812 [ # # ]: 0 : if (entry.offset != vhd->header.table_offset)
813 : : return -EINVAL;
814 : :
815 : 0 : err = posix_memalign(&_bat, VHD_SECTOR_SIZE, size);
816 [ # # ]: 0 : if (err)
817 : 0 : return -err;
818 : 0 : bat->bat = _bat;
819 : :
820 : 0 : err = vhd_journal_read(j, bat->bat, entry.size);
821 [ # # ]: 0 : if (err)
822 : : goto fail;
823 : :
824 : 0 : bat->spb = vhd->header.block_size >> VHD_SECTOR_SHIFT;
825 : 0 : bat->entries = vhd->header.max_bat_size;
826 : 0 : vhd_bat_in(bat);
827 : :
828 : : return 0;
829 : :
830 : : fail:
831 : 0 : free(bat->bat);
832 : 0 : bat->bat = NULL;
833 : 0 : return err;
834 : : }
835 : :
836 : : static int
837 : 0 : vhd_journal_read_batmap_header(vhd_journal_t *j, vhd_batmap_t *batmap)
838 : : {
839 : : int err;
840 : : void *buf;
841 : : size_t size;
842 : : vhd_journal_entry_t entry;
843 : :
844 : 0 : size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr));
845 : :
846 : 0 : err = vhd_journal_read_entry(j, &entry);
847 [ # # ]: 0 : if (err)
848 : 0 : return err;
849 : :
850 [ # # ]: 0 : if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BATMAP_H)
851 : : return -EINVAL;
852 : :
853 [ # # ]: 0 : if (entry.size != size)
854 : : return -EINVAL;
855 : :
856 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
857 [ # # ]: 0 : if (err)
858 : : return err;
859 : :
860 : 0 : err = vhd_journal_read(j, buf, entry.size);
861 [ # # ]: 0 : if (err) {
862 : 0 : free(buf);
863 : 0 : return err;
864 : : }
865 : :
866 : 0 : memcpy(&batmap->header, buf, sizeof(batmap->header));
867 : 0 : free(buf);
868 : :
869 : 0 : vhd_batmap_header_in(batmap);
870 : 0 : return vhd_validate_batmap_header(batmap);
871 : : }
872 : :
873 : : static int
874 : 0 : vhd_journal_read_batmap_map(vhd_journal_t *j, vhd_batmap_t *batmap)
875 : : {
876 : : int err;
877 : : vhd_journal_entry_t entry;
878 : : void *map;
879 : :
880 : 0 : err = vhd_journal_read_entry(j, &entry);
881 [ # # ]: 0 : if (err)
882 : 0 : return err;
883 : :
884 [ # # ]: 0 : if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BATMAP_M)
885 : : return -EINVAL;
886 : :
887 [ # # ]: 0 : if (entry.size != vhd_sectors_to_bytes(batmap->header.batmap_size))
888 : : return -EINVAL;
889 : :
890 [ # # ]: 0 : if (entry.offset != batmap->header.batmap_offset)
891 : : return -EINVAL;
892 : :
893 : 0 : err = posix_memalign(&map, VHD_SECTOR_SIZE, entry.size);
894 [ # # ]: 0 : if (err)
895 : 0 : return -err;
896 : :
897 : 0 : batmap->map = map;
898 : :
899 : 0 : err = vhd_journal_read(j, batmap->map, entry.size);
900 [ # # ]: 0 : if (err) {
901 : 0 : free(batmap->map);
902 : 0 : batmap->map = NULL;
903 : 0 : return err;
904 : : }
905 : :
906 : : return 0;
907 : : }
908 : :
909 : : static int
910 : 0 : vhd_journal_read_batmap(vhd_journal_t *j, vhd_batmap_t *batmap)
911 : : {
912 : : int err;
913 : :
914 : 0 : err = vhd_journal_read_batmap_header(j, batmap);
915 [ # # ]: 0 : if (err)
916 : : return err;
917 : :
918 : 0 : err = vhd_journal_read_batmap_map(j, batmap);
919 [ # # ]: 0 : if (err)
920 : : return err;
921 : :
922 : 0 : err = vhd_validate_batmap(&j->vhd, batmap);
923 [ # # ]: 0 : if (err) {
924 : 0 : free(batmap->map);
925 : 0 : batmap->map = NULL;
926 : 0 : return err;
927 : : }
928 : :
929 : : return 0;
930 : : }
931 : :
932 : : static int
933 : : vhd_journal_restore_footer(vhd_journal_t *j, vhd_footer_t *footer)
934 : : {
935 : 0 : return vhd_write_footer_at(&j->vhd, footer,
936 : 0 : j->header.vhd_footer_offset);
937 : : }
938 : :
939 : : static int
940 : : vhd_journal_restore_footer_copy(vhd_journal_t *j, vhd_footer_t *footer)
941 : : {
942 : 0 : return vhd_write_footer_at(&j->vhd, footer, 0);
943 : : }
944 : :
945 : : static int
946 : : vhd_journal_restore_header(vhd_journal_t *j, vhd_header_t *header)
947 : : {
948 : : off64_t off;
949 : : vhd_context_t *vhd;
950 : :
951 : 0 : vhd = &j->vhd;
952 : 0 : off = vhd->footer.data_offset;
953 : :
954 : 0 : return vhd_write_header_at(&j->vhd, header, off);
955 : : }
956 : :
957 : : static int
958 : 0 : vhd_journal_restore_locators(vhd_journal_t *j, char **locators, int locs)
959 : : {
960 : : size_t size;
961 : : vhd_context_t *vhd;
962 : : int i, n, lidx, err;
963 : 0 : vhd_parent_locator_t *loc;
964 : :
965 : 0 : lidx = 0;
966 : 0 : vhd = &j->vhd;
967 : :
968 : 0 : n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t);
969 : :
970 [ # # ]: 0 : for (i = 0; i < n && lidx < locs; i++) {
971 : 0 : loc = vhd->header.loc + i;
972 [ # # ]: 0 : if (loc->code == PLAT_CODE_NONE)
973 : 0 : continue;
974 : :
975 : 0 : err = vhd_seek(vhd, loc->data_offset, SEEK_SET);
976 [ # # ]: 0 : if (err)
977 : : return err;
978 : :
979 : 0 : size = vhd_parent_locator_size(loc);
980 : 0 : err = vhd_write(vhd, locators[lidx++], size);
981 [ # # ]: 0 : if (err)
982 : : return err;
983 : : }
984 : :
985 : : return 0;
986 : : }
987 : :
988 : : static int
989 : : vhd_journal_restore_bat(vhd_journal_t *j, vhd_bat_t *bat)
990 : : {
991 : 0 : return vhd_write_bat(&j->vhd, bat);
992 : : }
993 : :
994 : : static int
995 : : vhd_journal_restore_batmap(vhd_journal_t *j, vhd_batmap_t *batmap)
996 : : {
997 : 0 : return vhd_write_batmap(&j->vhd, batmap);
998 : : }
999 : :
1000 : : static int
1001 : 0 : vhd_journal_restore_metadata(vhd_journal_t *j)
1002 : : {
1003 : : off64_t off;
1004 : : char **locators;
1005 : : vhd_footer_t copy;
1006 : 0 : vhd_context_t *vhd;
1007 : : int i, locs, hlocs, err;
1008 : :
1009 : 0 : vhd = &j->vhd;
1010 : 0 : locs = 0;
1011 : 0 : hlocs = 0;
1012 : 0 : locators = NULL;
1013 : :
1014 : 0 : err = vhd_journal_seek(j, sizeof(vhd_journal_header_t), SEEK_SET);
1015 [ # # ]: 0 : if (err)
1016 : 0 : return err;
1017 : :
1018 : 0 : err = vhd_journal_read_footer(j, &vhd->footer);
1019 [ # # ]: 0 : if (err)
1020 : : return err;
1021 : :
1022 [ # # ]: 0 : if (!vhd_type_dynamic(vhd))
1023 : : goto restore;
1024 : :
1025 : 0 : err = vhd_journal_read_footer_copy(j, ©);
1026 [ # # ]: 0 : if (err)
1027 : : return err;
1028 : :
1029 : 0 : err = vhd_journal_read_header(j, &vhd->header);
1030 [ # # ]: 0 : if (err)
1031 : : return err;
1032 : :
1033 [ # # ]: 0 : for (hlocs = 0, i = 0; i < vhd_parent_locator_count(vhd); i++) {
1034 [ # # ]: 0 : if (vhd_validate_platform_code(vhd->header.loc[i].code))
1035 : : return err;
1036 : :
1037 [ # # ]: 0 : if (vhd->header.loc[i].code != PLAT_CODE_NONE)
1038 : 0 : hlocs++;
1039 : : }
1040 : :
1041 [ # # ]: 0 : if (hlocs) {
1042 : 0 : err = vhd_journal_read_locators(j, &locators, &locs);
1043 [ # # ]: 0 : if (err)
1044 : : return err;
1045 : :
1046 [ # # ]: 0 : if (hlocs != locs) {
1047 : : err = -EINVAL;
1048 : : goto out;
1049 : : }
1050 : : }
1051 : :
1052 : 0 : err = vhd_journal_read_bat(j, &vhd->bat);
1053 [ # # ]: 0 : if (err)
1054 : : goto out;
1055 : :
1056 [ # # ]: 0 : if (vhd_has_batmap(vhd)) {
1057 : 0 : err = vhd_journal_read_batmap(j, &vhd->batmap);
1058 [ # # ]: 0 : if (err)
1059 : : goto out;
1060 : : }
1061 : :
1062 : : restore:
1063 : 0 : off = vhd_journal_position(j);
1064 [ # # ]: 0 : if (off == (off64_t)-1) {
1065 : 0 : err = -errno;
1066 : 0 : goto out;
1067 : : }
1068 : :
1069 [ # # ]: 0 : if (j->header.journal_data_offset != off) {
1070 : : err = -EINVAL;
1071 : : goto out;
1072 : : }
1073 : :
1074 : 0 : err = vhd_journal_restore_footer(j, &vhd->footer);
1075 [ # # ]: 0 : if (err)
1076 : : goto out;
1077 : :
1078 [ # # ]: 0 : if (!vhd_type_dynamic(vhd))
1079 : : goto out;
1080 : :
1081 : 0 : err = vhd_journal_restore_footer_copy(j, ©);
1082 [ # # ]: 0 : if (err)
1083 : : goto out;
1084 : :
1085 : 0 : err = vhd_journal_restore_header(j, &vhd->header);
1086 [ # # ]: 0 : if (err)
1087 : : goto out;
1088 : :
1089 [ # # ]: 0 : if (locs) {
1090 : 0 : err = vhd_journal_restore_locators(j, locators, locs);
1091 [ # # ]: 0 : if (err)
1092 : : goto out;
1093 : : }
1094 : :
1095 : 0 : err = vhd_journal_restore_bat(j, &vhd->bat);
1096 [ # # ]: 0 : if (err)
1097 : : goto out;
1098 : :
1099 [ # # ]: 0 : if (vhd_has_batmap(vhd)) {
1100 : 0 : err = vhd_journal_restore_batmap(j, &vhd->batmap);
1101 [ # # ]: 0 : if (err)
1102 : : goto out;
1103 : : }
1104 : :
1105 : : err = 0;
1106 : :
1107 : : out:
1108 [ # # ]: 0 : if (locators) {
1109 [ # # ]: 0 : for (i = 0; i < locs; i++)
1110 : 0 : free(locators[i]);
1111 : 0 : free(locators);
1112 : : }
1113 : :
1114 [ # # ][ # # ]: 0 : if (!err && !vhd->is_block)
1115 : 0 : err = ftruncate(vhd->fd,
1116 : 0 : j->header.vhd_footer_offset +
1117 : : sizeof(vhd_footer_t));
1118 : :
1119 : 0 : return err;
1120 : : }
1121 : :
1122 : : static int
1123 : 0 : vhd_journal_disable_vhd(vhd_journal_t *j)
1124 : : {
1125 : : int err;
1126 : : vhd_context_t *vhd;
1127 : :
1128 : 0 : vhd = &j->vhd;
1129 : :
1130 : 0 : err = vhd_get_footer(vhd);
1131 [ # # ]: 0 : if (err)
1132 : : return err;
1133 : :
1134 : 0 : memcpy(&vhd->footer.cookie,
1135 : : VHD_POISON_COOKIE, sizeof(vhd->footer.cookie));
1136 : 0 : vhd->footer.checksum = vhd_checksum_footer(&vhd->footer);
1137 : :
1138 : 0 : err = vhd_write_footer(vhd, &vhd->footer);
1139 [ # # ]: 0 : if (err)
1140 : 0 : return err;
1141 : :
1142 : : return 0;
1143 : : }
1144 : :
1145 : : static int
1146 : 0 : vhd_journal_enable_vhd(vhd_journal_t *j)
1147 : : {
1148 : : int err;
1149 : : vhd_context_t *vhd;
1150 : :
1151 : 0 : vhd = &j->vhd;
1152 : :
1153 : 0 : err = vhd_get_footer(vhd);
1154 [ # # ]: 0 : if (err)
1155 : : return err;
1156 : :
1157 [ # # ]: 0 : if (!vhd_disabled(vhd))
1158 : : return 0;
1159 : :
1160 : 0 : memcpy(&vhd->footer.cookie, HD_COOKIE, sizeof(vhd->footer.cookie));
1161 : 0 : vhd->footer.checksum = vhd_checksum_footer(&vhd->footer);
1162 : :
1163 : 0 : err = vhd_write_footer(vhd, &vhd->footer);
1164 [ # # ]: 0 : if (err)
1165 : 0 : return err;
1166 : :
1167 : : return 0;
1168 : : }
1169 : :
1170 : : int
1171 : 0 : vhd_journal_close(vhd_journal_t *j)
1172 : : {
1173 [ # # ]: 0 : if (j->jfd)
1174 : 0 : close(j->jfd);
1175 : :
1176 : 0 : vhd_close(&j->vhd);
1177 : 0 : free(j->jname);
1178 : :
1179 : 0 : return 0;
1180 : : }
1181 : :
1182 : : int
1183 : 0 : vhd_journal_remove(vhd_journal_t *j)
1184 : : {
1185 : : int err;
1186 : :
1187 : 0 : err = vhd_journal_enable_vhd(j);
1188 [ # # ]: 0 : if (err)
1189 : : return err;
1190 : :
1191 [ # # ]: 0 : if (j->jfd) {
1192 : 0 : close(j->jfd);
1193 [ # # ]: 0 : if (!j->is_block)
1194 : 0 : unlink(j->jname);
1195 : : }
1196 : :
1197 : 0 : vhd_close(&j->vhd);
1198 : 0 : free(j->jname);
1199 : :
1200 : 0 : return 0;
1201 : : }
1202 : :
1203 : : int
1204 : 0 : vhd_journal_open(vhd_journal_t *j, const char *file, const char *jfile)
1205 : : {
1206 : : int err;
1207 : : vhd_context_t *vhd;
1208 : :
1209 : : memset(j, 0, sizeof(vhd_journal_t));
1210 : :
1211 : 0 : j->jfd = -1;
1212 : 0 : vhd = &j->vhd;
1213 : :
1214 : 0 : j->jname = strdup(jfile);
1215 [ # # ]: 0 : if (j->jname == NULL)
1216 : : return -ENOMEM;
1217 : :
1218 : 0 : j->jfd = open(j->jname, O_LARGEFILE | O_RDWR);
1219 [ # # ]: 0 : if (j->jfd == -1) {
1220 : 0 : err = -errno;
1221 : 0 : goto fail;
1222 : : }
1223 : :
1224 : 0 : err = vhd_test_file_fixed(j->jname, &j->is_block);
1225 [ # # ]: 0 : if (err)
1226 : : goto fail;
1227 : :
1228 : 0 : vhd->fd = open_optional_odirect(file, O_LARGEFILE | O_RDWR | O_DIRECT);
1229 [ # # ]: 0 : if (vhd->fd == -1) {
1230 : 0 : err = -errno;
1231 : 0 : goto fail;
1232 : : }
1233 : :
1234 : 0 : err = vhd_test_file_fixed(file, &vhd->is_block);
1235 [ # # ]: 0 : if (err)
1236 : : goto fail;
1237 : :
1238 : 0 : err = vhd_journal_read_journal_header(j, &j->header);
1239 [ # # ]: 0 : if (err)
1240 : : goto fail;
1241 : :
1242 : 0 : err = vhd_journal_restore_metadata(j);
1243 [ # # ]: 0 : if (err)
1244 : : goto fail;
1245 : :
1246 : 0 : close(vhd->fd);
1247 : 0 : free(vhd->bat.bat);
1248 : 0 : free(vhd->batmap.map);
1249 : :
1250 : 0 : err = vhd_open(vhd, file, VHD_OPEN_RDWR);
1251 [ # # ]: 0 : if (err)
1252 : : goto fail;
1253 : :
1254 : 0 : err = vhd_get_bat(vhd);
1255 [ # # ]: 0 : if (err)
1256 : : goto fail;
1257 : :
1258 [ # # ]: 0 : if (vhd_has_batmap(vhd)) {
1259 : 0 : err = vhd_get_batmap(vhd);
1260 [ # # ]: 0 : if (err)
1261 : : goto fail;
1262 : : }
1263 : :
1264 : 0 : err = vhd_journal_disable_vhd(j);
1265 [ # # ]: 0 : if (err)
1266 : : goto fail;
1267 : :
1268 : : return 0;
1269 : :
1270 : : fail:
1271 : 0 : vhd_journal_close(j);
1272 : 0 : return err;
1273 : : }
1274 : :
1275 : : int
1276 : 0 : vhd_journal_create(vhd_journal_t *j, const char *file, const char *jfile)
1277 : : {
1278 : : int err;
1279 : :
1280 : : memset(j, 0, sizeof(vhd_journal_t));
1281 : 0 : j->jfd = -1;
1282 : :
1283 : 0 : j->jname = strdup(jfile);
1284 [ # # ]: 0 : if (j->jname == NULL) {
1285 : : err = -ENOMEM;
1286 : : goto fail1;
1287 : : }
1288 : :
1289 [ # # ]: 0 : if (access(j->jname, F_OK) == 0) {
1290 : 0 : err = vhd_test_file_fixed(j->jname, &j->is_block);
1291 [ # # ]: 0 : if (err)
1292 : : goto fail1;
1293 : :
1294 [ # # ]: 0 : if (!j->is_block) {
1295 : : err = -EEXIST;
1296 : : goto fail1;
1297 : : }
1298 : : }
1299 : :
1300 [ # # ]: 0 : if (j->is_block)
1301 : 0 : j->jfd = open(j->jname, O_LARGEFILE | O_RDWR, 0644);
1302 : : else
1303 : 0 : j->jfd = open(j->jname,
1304 : : O_CREAT | O_TRUNC | O_LARGEFILE | O_RDWR, 0644);
1305 [ # # ]: 0 : if (j->jfd == -1) {
1306 : 0 : err = -errno;
1307 : 0 : goto fail1;
1308 : : }
1309 : :
1310 : 0 : err = vhd_open(&j->vhd, file, VHD_OPEN_RDWR | VHD_OPEN_STRICT);
1311 [ # # ]: 0 : if (err)
1312 : : goto fail1;
1313 : :
1314 : 0 : err = vhd_get_bat(&j->vhd);
1315 [ # # ]: 0 : if (err)
1316 : : goto fail2;
1317 : :
1318 [ # # ]: 0 : if (vhd_has_batmap(&j->vhd)) {
1319 : 0 : err = vhd_get_batmap(&j->vhd);
1320 [ # # ]: 0 : if (err)
1321 : : goto fail2;
1322 : : }
1323 : :
1324 : 0 : err = vhd_journal_add_journal_header(j);
1325 [ # # ]: 0 : if (err)
1326 : : goto fail2;
1327 : :
1328 : 0 : err = vhd_journal_add_metadata(j);
1329 [ # # ]: 0 : if (err)
1330 : : goto fail2;
1331 : :
1332 : 0 : err = vhd_journal_disable_vhd(j);
1333 [ # # ]: 0 : if (err)
1334 : : goto fail2;
1335 : :
1336 : 0 : err = vhd_journal_sync(j);
1337 [ # # ]: 0 : if (err)
1338 : : goto fail2;
1339 : :
1340 : : return 0;
1341 : :
1342 : : fail1:
1343 [ # # ]: 0 : if (j->jfd != -1) {
1344 : 0 : close(j->jfd);
1345 [ # # ]: 0 : if (!j->is_block)
1346 : 0 : unlink(j->jname);
1347 : : }
1348 : 0 : free(j->jname);
1349 : : memset(j, 0, sizeof(vhd_journal_t));
1350 : :
1351 : 0 : return err;
1352 : :
1353 : : fail2:
1354 : 0 : vhd_journal_remove(j);
1355 : 0 : return err;
1356 : : }
1357 : :
1358 : : int
1359 : 0 : vhd_journal_add_block(vhd_journal_t *j, uint32_t block, char mode)
1360 : : {
1361 : : int err;
1362 : : char *buf;
1363 : : off64_t off;
1364 : : size_t size;
1365 : : uint64_t blk;
1366 : 0 : vhd_context_t *vhd;
1367 : :
1368 : 0 : buf = NULL;
1369 : 0 : vhd = &j->vhd;
1370 : :
1371 [ # # ]: 0 : if (!vhd_type_dynamic(vhd))
1372 : 0 : return -EINVAL;
1373 : :
1374 : 0 : err = vhd_get_bat(vhd);
1375 [ # # ]: 0 : if (err)
1376 : : return err;
1377 : :
1378 [ # # ]: 0 : if (block >= vhd->bat.entries)
1379 : : return -ERANGE;
1380 : :
1381 : 0 : blk = vhd->bat.bat[block];
1382 [ # # ]: 0 : if (blk == DD_BLK_UNUSED)
1383 : : return 0;
1384 : :
1385 : 0 : off = vhd_sectors_to_bytes(blk);
1386 : :
1387 [ # # ]: 0 : if (mode & VHD_JOURNAL_METADATA) {
1388 : 0 : size = vhd_sectors_to_bytes(vhd->bm_secs);
1389 : :
1390 : 0 : err = vhd_read_bitmap(vhd, block, &buf);
1391 [ # # ]: 0 : if (err)
1392 : : return err;
1393 : :
1394 : 0 : err = vhd_journal_update(j, off, buf, size,
1395 : : VHD_JOURNAL_ENTRY_TYPE_DATA);
1396 : :
1397 : 0 : free(buf);
1398 : :
1399 [ # # ]: 0 : if (err)
1400 : : return err;
1401 : : }
1402 : :
1403 [ # # ]: 0 : if (mode & VHD_JOURNAL_DATA) {
1404 : 0 : off += vhd_sectors_to_bytes(vhd->bm_secs);
1405 : 0 : size = vhd_sectors_to_bytes(vhd->spb);
1406 : :
1407 : 0 : err = vhd_read_block(vhd, block, &buf);
1408 [ # # ]: 0 : if (err)
1409 : : return err;
1410 : :
1411 : 0 : err = vhd_journal_update(j, off, buf, size,
1412 : : VHD_JOURNAL_ENTRY_TYPE_DATA);
1413 : 0 : free(buf);
1414 : :
1415 [ # # ]: 0 : if (err)
1416 : : return err;
1417 : : }
1418 : :
1419 : 0 : return vhd_journal_sync(j);
1420 : : }
1421 : :
1422 : : /*
1423 : : * commit indicates the transaction completed
1424 : : * successfully and we can remove the undo log
1425 : : */
1426 : : int
1427 : 0 : vhd_journal_commit(vhd_journal_t *j)
1428 : : {
1429 : : int err;
1430 : :
1431 : 0 : j->header.journal_data_entries = 0;
1432 : 0 : j->header.journal_metadata_entries = 0;
1433 : 0 : j->header.journal_data_offset = 0;
1434 : 0 : j->header.journal_metadata_offset = 0;
1435 : :
1436 : 0 : err = vhd_journal_write_header(j, &j->header);
1437 [ # # ]: 0 : if (err)
1438 : : return err;
1439 : :
1440 [ # # ]: 0 : if (!j->is_block)
1441 : 0 : err = vhd_journal_truncate(j, sizeof(vhd_journal_header_t));
1442 [ # # ]: 0 : if (err)
1443 : 0 : return -errno;
1444 : :
1445 : : return 0;
1446 : : }
1447 : :
1448 : : /*
1449 : : * revert indicates the transaction failed
1450 : : * and we should revert any changes via the undo log
1451 : : */
1452 : : int
1453 : 0 : vhd_journal_revert(vhd_journal_t *j)
1454 : : {
1455 : : int i, err;
1456 : : char *file;
1457 : : void *buf;
1458 : : vhd_context_t *vhd;
1459 : : vhd_journal_entry_t entry;
1460 : :
1461 : 0 : err = 0;
1462 : 0 : vhd = &j->vhd;
1463 : 0 : buf = NULL;
1464 : :
1465 : 0 : file = strdup(vhd->file);
1466 [ # # ]: 0 : if (!file)
1467 : 0 : return -ENOMEM;
1468 : :
1469 : 0 : vhd_close(&j->vhd);
1470 : 0 : j->vhd.fd = open_optional_odirect(file, O_RDWR | O_DIRECT | O_LARGEFILE);
1471 [ # # ]: 0 : if (j->vhd.fd == -1) {
1472 : 0 : free(file);
1473 : 0 : return -errno;
1474 : : }
1475 : :
1476 : 0 : err = vhd_test_file_fixed(file, &vhd->is_block);
1477 [ # # ]: 0 : if (err) {
1478 : 0 : free(file);
1479 : 0 : return err;
1480 : : }
1481 : :
1482 : 0 : err = vhd_journal_restore_metadata(j);
1483 [ # # ]: 0 : if (err) {
1484 : 0 : free(file);
1485 : 0 : return err;
1486 : : }
1487 : :
1488 : 0 : close(vhd->fd);
1489 : 0 : free(vhd->bat.bat);
1490 : 0 : free(vhd->batmap.map);
1491 : :
1492 : 0 : err = vhd_open(vhd, file, VHD_OPEN_RDWR);
1493 : 0 : free(file);
1494 [ # # ]: 0 : if (err)
1495 : : return err;
1496 : :
1497 : 0 : err = vhd_journal_seek(j, j->header.journal_data_offset, SEEK_SET);
1498 [ # # ]: 0 : if (err)
1499 : : return err;
1500 : :
1501 [ # # ]: 0 : for (i = 0; i < j->header.journal_data_entries; i++) {
1502 : 0 : err = vhd_journal_read_entry(j, &entry);
1503 [ # # ]: 0 : if (err)
1504 : : goto end;
1505 : :
1506 : 0 : err = posix_memalign(&buf, VHD_SECTOR_SIZE, entry.size);
1507 [ # # ]: 0 : if (err) {
1508 : 0 : err = -err;
1509 : 0 : buf = NULL;
1510 : 0 : goto end;
1511 : : }
1512 : :
1513 : 0 : err = vhd_journal_read(j, buf, entry.size);
1514 [ # # ]: 0 : if (err)
1515 : : goto end;
1516 : :
1517 : 0 : err = vhd_journal_validate_entry_data(&entry, buf);
1518 [ # # ]: 0 : if (err)
1519 : : goto end;
1520 : :
1521 : 0 : err = vhd_seek(vhd, entry.offset, SEEK_SET);
1522 [ # # ]: 0 : if (err)
1523 : : goto end;
1524 : :
1525 : 0 : err = vhd_write(vhd, buf, entry.size);
1526 [ # # ]: 0 : if (err)
1527 : : goto end;
1528 : :
1529 : 0 : err = 0;
1530 : :
1531 : : end:
1532 : 0 : free(buf);
1533 : 0 : buf = NULL;
1534 [ # # ]: 0 : if (err)
1535 : : break;
1536 : : }
1537 : :
1538 [ # # ]: 0 : if (err)
1539 : : return err;
1540 : :
1541 [ # # ]: 0 : if (!vhd->is_block) {
1542 : 0 : err = ftruncate(vhd->fd, j->header.vhd_footer_offset +
1543 : : sizeof(vhd_footer_t));
1544 [ # # ]: 0 : if (err)
1545 : 0 : return -errno;
1546 : : }
1547 : :
1548 : 0 : return vhd_journal_sync(j);
1549 : : }
|