ia64/xen-unstable

view tools/blktap2/vhd/lib/libvhd-journal.c @ 19817:b7f73a7f3078

blktap2: portability fixes for NetBSD

- Use standard off_t and lseek() instead of non-portable off64_t and
lseek64()
- Use uuid API as documented in DCE 1.1 RPC specification
- Add NetBSD implementation for blk_getimagesize() and
blk_getsectorsize()
- Use blk_getimagesize() and blk_getsectorsize()
- Fix uuid header check

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 23 17:24:14 2009 +0100 (2009-06-23)
parents 1c627434605e
children f1fec38c8228
line source
1 /* Copyright (c) 2008, XenSource Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of XenSource Inc. nor the names of its contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <stdio.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
34 #include "atomicio.h"
35 #include "libvhd-journal.h"
37 #define VHD_JOURNAL_ENTRY_TYPE_FOOTER_P 1
38 #define VHD_JOURNAL_ENTRY_TYPE_FOOTER_C 2
39 #define VHD_JOURNAL_ENTRY_TYPE_HEADER 3
40 #define VHD_JOURNAL_ENTRY_TYPE_LOCATOR 4
41 #define VHD_JOURNAL_ENTRY_TYPE_BAT 5
42 #define VHD_JOURNAL_ENTRY_TYPE_BATMAP_H 6
43 #define VHD_JOURNAL_ENTRY_TYPE_BATMAP_M 7
44 #define VHD_JOURNAL_ENTRY_TYPE_DATA 8
46 typedef struct vhd_journal_entry {
47 uint64_t cookie;
48 uint32_t type;
49 uint32_t size;
50 uint64_t offset;
51 uint32_t checksum;
52 } vhd_journal_entry_t;
54 static inline int
55 vhd_journal_seek(vhd_journal_t *j, off_t offset, int whence)
56 {
57 off_t off;
59 off = lseek(j->jfd, offset, whence);
60 if (off == (off_t)-1)
61 return -errno;
63 return 0;
64 }
66 static inline off_t
67 vhd_journal_position(vhd_journal_t *j)
68 {
69 return lseek(j->jfd, 0, SEEK_CUR);
70 }
72 static inline int
73 vhd_journal_read(vhd_journal_t *j, void *buf, size_t size)
74 {
75 ssize_t ret;
77 errno = 0;
79 ret = atomicio(read, j->jfd, buf, size);
80 if (ret != size)
81 return (errno ? -errno : -EIO);
83 return 0;
84 }
86 static inline int
87 vhd_journal_write(vhd_journal_t *j, void *buf, size_t size)
88 {
89 ssize_t ret;
91 errno = 0;
93 ret = atomicio(vwrite, j->jfd, buf, size);
94 if (ret != size)
95 return (errno ? -errno : -EIO);
97 return 0;
98 }
100 static inline int
101 vhd_journal_truncate(vhd_journal_t *j, off_t length)
102 {
103 int err;
105 err = ftruncate(j->jfd, length);
106 if (err == -1)
107 return -errno;
109 return 0;
110 }
112 static inline int
113 vhd_journal_sync(vhd_journal_t *j)
114 {
115 int err;
117 err = fdatasync(j->jfd);
118 if (err)
119 return -errno;
121 return 0;
122 }
124 static inline void
125 vhd_journal_header_in(vhd_journal_header_t *header)
126 {
127 BE64_IN(&header->vhd_footer_offset);
128 BE32_IN(&header->journal_data_entries);
129 BE32_IN(&header->journal_metadata_entries);
130 BE64_IN(&header->journal_data_offset);
131 BE64_IN(&header->journal_metadata_offset);
132 }
134 static inline void
135 vhd_journal_header_out(vhd_journal_header_t *header)
136 {
137 BE64_OUT(&header->vhd_footer_offset);
138 BE32_OUT(&header->journal_data_entries);
139 BE32_OUT(&header->journal_metadata_entries);
140 BE64_OUT(&header->journal_data_offset);
141 BE64_OUT(&header->journal_metadata_offset);
142 }
144 static int
145 vhd_journal_validate_header(vhd_journal_t *j, vhd_journal_header_t *header)
146 {
147 int err;
148 off_t eof;
150 if (memcmp(header->cookie,
151 VHD_JOURNAL_HEADER_COOKIE, sizeof(header->cookie)))
152 return -EINVAL;
154 err = vhd_journal_seek(j, j->header.journal_eof, SEEK_SET);
155 if (err)
156 return err;
158 eof = vhd_journal_position(j);
159 if (eof == (off_t)-1)
160 return -errno;
162 if (j->header.journal_data_offset > j->header.journal_eof)
163 return -EINVAL;
165 if (j->header.journal_metadata_offset > j->header.journal_eof)
166 return -EINVAL;
168 return 0;
169 }
171 static int
172 vhd_journal_read_journal_header(vhd_journal_t *j, vhd_journal_header_t *header)
173 {
174 int err;
175 size_t size;
177 size = sizeof(vhd_journal_header_t);
178 err = vhd_journal_seek(j, 0, SEEK_SET);
179 if (err)
180 return err;
182 err = vhd_journal_read(j, header, size);
183 if (err)
184 return err;
186 vhd_journal_header_in(header);
188 return vhd_journal_validate_header(j, header);
189 }
191 static int
192 vhd_journal_write_header(vhd_journal_t *j, vhd_journal_header_t *header)
193 {
194 int err;
195 size_t size;
196 vhd_journal_header_t h;
198 memcpy(&h, header, sizeof(vhd_journal_header_t));
200 err = vhd_journal_validate_header(j, &h);
201 if (err)
202 return err;
204 vhd_journal_header_out(&h);
205 size = sizeof(vhd_journal_header_t);
207 err = vhd_journal_seek(j, 0, SEEK_SET);
208 if (err)
209 return err;
211 err = vhd_journal_write(j, &h, size);
212 if (err)
213 return err;
215 return 0;
216 }
218 static int
219 vhd_journal_add_journal_header(vhd_journal_t *j)
220 {
221 int err;
222 off_t off;
223 vhd_context_t *vhd;
225 vhd = &j->vhd;
226 memset(&j->header, 0, sizeof(vhd_journal_header_t));
228 err = vhd_seek(vhd, 0, SEEK_END);
229 if (err)
230 return err;
232 off = vhd_position(vhd);
233 if (off == (off_t)-1)
234 return -errno;
236 err = vhd_get_footer(vhd);
237 if (err)
238 return err;
240 uuid_copy(j->header.uuid, vhd->footer.uuid);
241 memcpy(j->header.cookie,
242 VHD_JOURNAL_HEADER_COOKIE, sizeof(j->header.cookie));
243 j->header.vhd_footer_offset = off - sizeof(vhd_footer_t);
244 j->header.journal_eof = sizeof(vhd_journal_header_t);
246 return vhd_journal_write_header(j, &j->header);
247 }
249 static void
250 vhd_journal_entry_in(vhd_journal_entry_t *entry)
251 {
252 BE32_IN(&entry->type);
253 BE32_IN(&entry->size);
254 BE64_IN(&entry->offset);
255 BE64_IN(&entry->cookie);
256 BE32_IN(&entry->checksum);
257 }
259 static void
260 vhd_journal_entry_out(vhd_journal_entry_t *entry)
261 {
262 BE32_OUT(&entry->type);
263 BE32_OUT(&entry->size);
264 BE64_OUT(&entry->offset);
265 BE64_OUT(&entry->cookie);
266 BE32_OUT(&entry->checksum);
267 }
269 static uint32_t
270 vhd_journal_checksum_entry(vhd_journal_entry_t *entry, char *buf, size_t size)
271 {
272 int i;
273 unsigned char *blob;
274 uint32_t checksum, tmp;
276 checksum = 0;
277 tmp = entry->checksum;
278 entry->checksum = 0;
280 blob = (unsigned char *)entry;
281 for (i = 0; i < sizeof(vhd_journal_entry_t); i++)
282 checksum += blob[i];
284 blob = (unsigned char *)buf;
285 for (i = 0; i < size; i++)
286 checksum += blob[i];
288 entry->checksum = tmp;
289 return ~checksum;
290 }
292 static int
293 vhd_journal_validate_entry(vhd_journal_entry_t *entry)
294 {
295 if (entry->size == 0)
296 return -EINVAL;
298 if (entry->size & (VHD_SECTOR_SIZE - 1))
299 return -EINVAL;
301 if (entry->cookie != VHD_JOURNAL_ENTRY_COOKIE)
302 return -EINVAL;
304 return 0;
305 }
307 static int
308 vhd_journal_read_entry(vhd_journal_t *j, vhd_journal_entry_t *entry)
309 {
310 int err;
312 err = vhd_journal_read(j, entry, sizeof(vhd_journal_entry_t));
313 if (err)
314 return err;
316 vhd_journal_entry_in(entry);
317 return vhd_journal_validate_entry(entry);
318 }
320 static int
321 vhd_journal_write_entry(vhd_journal_t *j, vhd_journal_entry_t *entry)
322 {
323 int err;
324 vhd_journal_entry_t e;
326 err = vhd_journal_validate_entry(entry);
327 if (err)
328 return err;
330 memcpy(&e, entry, sizeof(vhd_journal_entry_t));
331 vhd_journal_entry_out(&e);
333 err = vhd_journal_write(j, &e, sizeof(vhd_journal_entry_t));
334 if (err)
335 err;
337 return 0;
338 }
340 static int
341 vhd_journal_validate_entry_data(vhd_journal_entry_t *entry, char *buf)
342 {
343 int err;
344 uint32_t checksum;
346 err = 0;
347 checksum = vhd_journal_checksum_entry(entry, buf, entry->size);
349 if (checksum != entry->checksum)
350 return -EINVAL;
352 return err;
353 }
355 static int
356 vhd_journal_update(vhd_journal_t *j, off_t offset,
357 char *buf, size_t size, uint32_t type)
358 {
359 int err;
360 off_t eof;
361 uint64_t *off, off_bak;
362 uint32_t *entries;
363 vhd_journal_entry_t entry;
365 entry.type = type;
366 entry.size = size;
367 entry.offset = offset;
368 entry.cookie = VHD_JOURNAL_ENTRY_COOKIE;
369 entry.checksum = vhd_journal_checksum_entry(&entry, buf, size);
371 err = vhd_journal_seek(j, j->header.journal_eof, SEEK_SET);
372 if (err)
373 return err;
375 err = vhd_journal_write_entry(j, &entry);
376 if (err)
377 goto fail;
379 err = vhd_journal_write(j, buf, size);
380 if (err)
381 goto fail;
383 if (type == VHD_JOURNAL_ENTRY_TYPE_DATA) {
384 off = &j->header.journal_data_offset;
385 entries = &j->header.journal_data_entries;
386 } else {
387 off = &j->header.journal_metadata_offset;
388 entries = &j->header.journal_metadata_entries;
389 }
391 off_bak = *off;
392 if (!(*entries)++)
393 *off = j->header.journal_eof;
394 j->header.journal_eof += (size + sizeof(vhd_journal_entry_t));
396 err = vhd_journal_write_header(j, &j->header);
397 if (err) {
398 if (!--(*entries))
399 *off = off_bak;
400 j->header.journal_eof -= (size + sizeof(vhd_journal_entry_t));
401 goto fail;
402 }
404 return 0;
406 fail:
407 if (!j->is_block)
408 vhd_journal_truncate(j, j->header.journal_eof);
409 return err;
410 }
412 static int
413 vhd_journal_add_footer(vhd_journal_t *j)
414 {
415 int err;
416 off_t off;
417 vhd_context_t *vhd;
418 vhd_footer_t footer;
420 vhd = &j->vhd;
422 err = vhd_seek(vhd, 0, SEEK_END);
423 if (err)
424 return err;
426 off = vhd_position(vhd);
427 if (off == (off_t)-1)
428 return -errno;
430 err = vhd_read_footer_at(vhd, &footer, off - sizeof(vhd_footer_t));
431 if (err)
432 return err;
434 vhd_footer_out(&footer);
435 err = vhd_journal_update(j, off - sizeof(vhd_footer_t),
436 (char *)&footer,
437 sizeof(vhd_footer_t),
438 VHD_JOURNAL_ENTRY_TYPE_FOOTER_P);
439 if (err)
440 return err;
442 if (!vhd_type_dynamic(vhd))
443 return 0;
445 err = vhd_read_footer_at(vhd, &footer, 0);
446 if (err)
447 return err;
449 vhd_footer_out(&footer);
450 err = vhd_journal_update(j, 0,
451 (char *)&footer,
452 sizeof(vhd_footer_t),
453 VHD_JOURNAL_ENTRY_TYPE_FOOTER_C);
455 return err;
456 }
458 static int
459 vhd_journal_add_header(vhd_journal_t *j)
460 {
461 int err;
462 off_t off;
463 vhd_context_t *vhd;
464 vhd_header_t header;
466 vhd = &j->vhd;
468 err = vhd_read_header(vhd, &header);
469 if (err)
470 return err;
472 off = vhd->footer.data_offset;
474 vhd_header_out(&header);
475 err = vhd_journal_update(j, off,
476 (char *)&header,
477 sizeof(vhd_header_t),
478 VHD_JOURNAL_ENTRY_TYPE_HEADER);
480 return err;
481 }
483 static int
484 vhd_journal_add_locators(vhd_journal_t *j)
485 {
486 int i, n, err;
487 vhd_context_t *vhd;
489 vhd = &j->vhd;
491 err = vhd_get_header(vhd);
492 if (err)
493 return err;
495 n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t);
496 for (i = 0; i < n; i++) {
497 char *buf;
498 off_t off;
499 size_t size;
500 vhd_parent_locator_t *loc;
502 loc = vhd->header.loc + i;
503 err = vhd_validate_platform_code(loc->code);
504 if (err)
505 return err;
507 if (loc->code == PLAT_CODE_NONE)
508 continue;
510 off = loc->data_offset;
511 size = vhd_parent_locator_size(loc);
513 err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
514 if (err)
515 return -err;
517 err = vhd_seek(vhd, off, SEEK_SET);
518 if (err)
519 goto end;
521 err = vhd_read(vhd, buf, size);
522 if (err)
523 goto end;
525 err = vhd_journal_update(j, off, buf, size,
526 VHD_JOURNAL_ENTRY_TYPE_LOCATOR);
527 if (err)
528 goto end;
530 err = 0;
532 end:
533 free(buf);
534 if (err)
535 break;
536 }
538 return err;
539 }
541 static int
542 vhd_journal_add_bat(vhd_journal_t *j)
543 {
544 int err;
545 off_t off;
546 size_t size;
547 vhd_bat_t bat;
548 vhd_context_t *vhd;
550 vhd = &j->vhd;
552 err = vhd_get_header(vhd);
553 if (err)
554 return err;
556 err = vhd_read_bat(vhd, &bat);
557 if (err)
558 return err;
560 off = vhd->header.table_offset;
561 size = vhd_bytes_padded(bat.entries * sizeof(uint32_t));
563 vhd_bat_out(&bat);
564 err = vhd_journal_update(j, off, (char *)bat.bat, size,
565 VHD_JOURNAL_ENTRY_TYPE_BAT);
567 free(bat.bat);
568 return err;
569 }
571 static int
572 vhd_journal_add_batmap(vhd_journal_t *j)
573 {
574 int err;
575 off_t off;
576 size_t size;
577 vhd_context_t *vhd;
578 vhd_batmap_t batmap;
580 vhd = &j->vhd;
582 err = vhd_batmap_header_offset(vhd, &off);
583 if (err)
584 return err;
586 err = vhd_read_batmap(vhd, &batmap);
587 if (err)
588 return err;
590 size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr));
592 vhd_batmap_header_out(&batmap);
593 err = vhd_journal_update(j, off, (char *)&batmap.header, size,
594 VHD_JOURNAL_ENTRY_TYPE_BATMAP_H);
595 if (err)
596 goto out;
598 vhd_batmap_header_in(&batmap);
599 off = batmap.header.batmap_offset;
600 size = vhd_sectors_to_bytes(batmap.header.batmap_size);
602 err = vhd_journal_update(j, off, batmap.map, size,
603 VHD_JOURNAL_ENTRY_TYPE_BATMAP_M);
605 out:
606 free(batmap.map);
607 return err;
608 }
610 static int
611 vhd_journal_add_metadata(vhd_journal_t *j)
612 {
613 int err;
614 off_t eof;
615 vhd_context_t *vhd;
617 vhd = &j->vhd;
619 err = vhd_journal_add_footer(j);
620 if (err)
621 return err;
623 if (!vhd_type_dynamic(vhd))
624 return 0;
626 err = vhd_journal_add_header(j);
627 if (err)
628 return err;
630 err = vhd_journal_add_locators(j);
631 if (err)
632 return err;
634 err = vhd_journal_add_bat(j);
635 if (err)
636 return err;
638 if (vhd_has_batmap(vhd)) {
639 err = vhd_journal_add_batmap(j);
640 if (err)
641 return err;
642 }
644 j->header.journal_data_offset = j->header.journal_eof;
645 return vhd_journal_write_header(j, &j->header);
646 }
648 static int
649 __vhd_journal_read_footer(vhd_journal_t *j,
650 vhd_footer_t *footer, uint32_t type)
651 {
652 int err;
653 vhd_journal_entry_t entry;
655 err = vhd_journal_read_entry(j, &entry);
656 if (err)
657 return err;
659 if (entry.type != type)
660 return -EINVAL;
662 if (entry.size != sizeof(vhd_footer_t))
663 return -EINVAL;
665 err = vhd_journal_read(j, footer, entry.size);
666 if (err)
667 return err;
669 vhd_footer_in(footer);
670 return vhd_validate_footer(footer);
671 }
673 static int
674 vhd_journal_read_footer(vhd_journal_t *j, vhd_footer_t *footer)
675 {
676 return __vhd_journal_read_footer(j, footer,
677 VHD_JOURNAL_ENTRY_TYPE_FOOTER_P);
678 }
680 static int
681 vhd_journal_read_footer_copy(vhd_journal_t *j, vhd_footer_t *footer)
682 {
683 return __vhd_journal_read_footer(j, footer,
684 VHD_JOURNAL_ENTRY_TYPE_FOOTER_C);
685 }
687 static int
688 vhd_journal_read_header(vhd_journal_t *j, vhd_header_t *header)
689 {
690 int err;
691 vhd_journal_entry_t entry;
693 err = vhd_journal_read_entry(j, &entry);
694 if (err)
695 return err;
697 if (entry.type != VHD_JOURNAL_ENTRY_TYPE_HEADER)
698 return -EINVAL;
700 if (entry.size != sizeof(vhd_header_t))
701 return -EINVAL;
703 err = vhd_journal_read(j, header, entry.size);
704 if (err)
705 return err;
707 vhd_header_in(header);
708 return vhd_validate_header(header);
709 }
711 static int
712 vhd_journal_read_locators(vhd_journal_t *j, char ***locators, int *locs)
713 {
714 int err, n, _locs;
715 char **_locators, *buf;
716 off_t pos;
717 vhd_journal_entry_t entry;
719 _locs = 0;
720 *locs = 0;
721 *locators = NULL;
723 n = sizeof(j->vhd.header.loc) / sizeof(vhd_parent_locator_t);
724 _locators = calloc(n, sizeof(char *));
725 if (!_locators)
726 return -ENOMEM;
728 for (;;) {
729 buf = NULL;
731 pos = vhd_journal_position(j);
732 err = vhd_journal_read_entry(j, &entry);
733 if (err)
734 goto fail;
736 if (entry.type != VHD_JOURNAL_ENTRY_TYPE_LOCATOR) {
737 err = vhd_journal_seek(j, pos, SEEK_SET);
738 if (err)
739 goto fail;
740 break;
741 }
743 if (_locs >= n) {
744 err = -EINVAL;
745 goto fail;
746 }
748 err = posix_memalign((void **)&buf,
749 VHD_SECTOR_SIZE, entry.size);
750 if (err) {
751 err = -err;
752 buf = NULL;
753 goto fail;
754 }
756 err = vhd_journal_read(j, buf, entry.size);
757 if (err)
758 goto fail;
760 _locators[_locs++] = buf;
761 err = 0;
762 }
765 *locs = _locs;
766 *locators = _locators;
768 return 0;
770 fail:
771 if (_locators) {
772 for (n = 0; n < _locs; n++)
773 free(_locators[n]);
774 free(_locators);
775 }
776 return err;
777 }
779 static int
780 vhd_journal_read_bat(vhd_journal_t *j, vhd_bat_t *bat)
781 {
782 int err;
783 size_t size;
784 vhd_context_t *vhd;
785 vhd_journal_entry_t entry;
787 vhd = &j->vhd;
789 size = vhd_bytes_padded(vhd->header.max_bat_size * sizeof(uint32_t));
791 err = vhd_journal_read_entry(j, &entry);
792 if (err)
793 return err;
795 if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BAT)
796 return -EINVAL;
798 if (entry.size != size)
799 return -EINVAL;
801 if (entry.offset != vhd->header.table_offset)
802 return -EINVAL;
804 err = posix_memalign((void **)&bat->bat, VHD_SECTOR_SIZE, size);
805 if (err)
806 return -err;
808 err = vhd_journal_read(j, bat->bat, entry.size);
809 if (err)
810 goto fail;
812 bat->spb = vhd->header.block_size >> VHD_SECTOR_SHIFT;
813 bat->entries = vhd->header.max_bat_size;
814 vhd_bat_in(bat);
816 return 0;
818 fail:
819 free(bat->bat);
820 bat->bat = NULL;
821 return err;
822 }
824 static int
825 vhd_journal_read_batmap_header(vhd_journal_t *j, vhd_batmap_t *batmap)
826 {
827 int err;
828 char *buf;
829 size_t size;
830 vhd_journal_entry_t entry;
832 size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr));
834 err = vhd_journal_read_entry(j, &entry);
835 if (err)
836 return err;
838 if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BATMAP_H)
839 return -EINVAL;
841 if (entry.size != size)
842 return -EINVAL;
844 err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
845 if (err)
846 return err;
848 err = vhd_journal_read(j, buf, entry.size);
849 if (err) {
850 free(buf);
851 return err;
852 }
854 memcpy(&batmap->header, buf, sizeof(batmap->header));
856 vhd_batmap_header_in(batmap);
857 return vhd_validate_batmap_header(batmap);
858 }
860 static int
861 vhd_journal_read_batmap_map(vhd_journal_t *j, vhd_batmap_t *batmap)
862 {
863 int err;
864 vhd_journal_entry_t entry;
866 err = vhd_journal_read_entry(j, &entry);
867 if (err)
868 return err;
870 if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BATMAP_M)
871 return -EINVAL;
873 if (entry.size != vhd_sectors_to_bytes(batmap->header.batmap_size))
874 return -EINVAL;
876 if (entry.offset != batmap->header.batmap_offset)
877 return -EINVAL;
879 err = posix_memalign((void **)&batmap->map,
880 VHD_SECTOR_SIZE, entry.size);
881 if (err)
882 return -err;
884 err = vhd_journal_read(j, batmap->map, entry.size);
885 if (err) {
886 free(batmap->map);
887 batmap->map = NULL;
888 return err;
889 }
891 return 0;
892 }
894 static int
895 vhd_journal_read_batmap(vhd_journal_t *j, vhd_batmap_t *batmap)
896 {
897 int err;
899 err = vhd_journal_read_batmap_header(j, batmap);
900 if (err)
901 return err;
903 err = vhd_journal_read_batmap_map(j, batmap);
904 if (err)
905 return err;
907 err = vhd_validate_batmap(batmap);
908 if (err) {
909 free(batmap->map);
910 batmap->map = NULL;
911 return err;
912 }
914 return 0;
915 }
917 static int
918 vhd_journal_restore_footer(vhd_journal_t *j, vhd_footer_t *footer)
919 {
920 return vhd_write_footer_at(&j->vhd, footer,
921 j->header.vhd_footer_offset);
922 }
924 static int
925 vhd_journal_restore_footer_copy(vhd_journal_t *j, vhd_footer_t *footer)
926 {
927 return vhd_write_footer_at(&j->vhd, footer, 0);
928 }
930 static int
931 vhd_journal_restore_header(vhd_journal_t *j, vhd_header_t *header)
932 {
933 off_t off;
934 vhd_context_t *vhd;
936 vhd = &j->vhd;
937 off = vhd->footer.data_offset;
939 return vhd_write_header_at(&j->vhd, header, off);
940 }
942 static int
943 vhd_journal_restore_locators(vhd_journal_t *j, char **locators, int locs)
944 {
945 size_t size;
946 vhd_context_t *vhd;
947 int i, n, lidx, err;
948 vhd_parent_locator_t *loc;
950 lidx = 0;
951 vhd = &j->vhd;
953 n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t);
955 for (i = 0; i < n && lidx < locs; i++) {
956 loc = vhd->header.loc + i;
957 if (loc->code == PLAT_CODE_NONE)
958 continue;
960 err = vhd_seek(vhd, loc->data_offset, SEEK_SET);
961 if (err)
962 return err;
964 size = vhd_parent_locator_size(loc);
965 err = vhd_write(vhd, locators[lidx++], size);
966 if (err)
967 return err;
968 }
970 return 0;
971 }
973 static int
974 vhd_journal_restore_bat(vhd_journal_t *j, vhd_bat_t *bat)
975 {
976 return vhd_write_bat(&j->vhd, bat);
977 }
979 static int
980 vhd_journal_restore_batmap(vhd_journal_t *j, vhd_batmap_t *batmap)
981 {
982 return vhd_write_batmap(&j->vhd, batmap);
983 }
985 static int
986 vhd_journal_restore_metadata(vhd_journal_t *j)
987 {
988 off_t off;
989 char **locators;
990 vhd_footer_t copy;
991 vhd_context_t *vhd;
992 int i, locs, hlocs, err;
994 vhd = &j->vhd;
995 locs = 0;
996 hlocs = 0;
997 locators = NULL;
999 err = vhd_journal_seek(j, sizeof(vhd_journal_header_t), SEEK_SET);
1000 if (err)
1001 return err;
1003 err = vhd_journal_read_footer(j, &vhd->footer);
1004 if (err)
1005 return err;
1007 if (!vhd_type_dynamic(vhd))
1008 goto restore;
1010 err = vhd_journal_read_footer_copy(j, &copy);
1011 if (err)
1012 return err;
1014 err = vhd_journal_read_header(j, &vhd->header);
1015 if (err)
1016 return err;
1018 for (hlocs = 0, i = 0; i < vhd_parent_locator_count(vhd); i++) {
1019 if (vhd_validate_platform_code(vhd->header.loc[i].code))
1020 return err;
1022 if (vhd->header.loc[i].code != PLAT_CODE_NONE)
1023 hlocs++;
1026 if (hlocs) {
1027 err = vhd_journal_read_locators(j, &locators, &locs);
1028 if (err)
1029 return err;
1031 if (hlocs != locs) {
1032 err = -EINVAL;
1033 goto out;
1037 err = vhd_journal_read_bat(j, &vhd->bat);
1038 if (err)
1039 goto out;
1041 if (vhd_has_batmap(vhd)) {
1042 err = vhd_journal_read_batmap(j, &vhd->batmap);
1043 if (err)
1044 goto out;
1047 restore:
1048 off = vhd_journal_position(j);
1049 if (off == (off_t)-1)
1050 return -errno;
1052 if (j->header.journal_data_offset != off)
1053 return -EINVAL;
1055 err = vhd_journal_restore_footer(j, &vhd->footer);
1056 if (err)
1057 goto out;
1059 if (!vhd_type_dynamic(vhd))
1060 goto out;
1062 err = vhd_journal_restore_footer_copy(j, &copy);
1063 if (err)
1064 goto out;
1066 err = vhd_journal_restore_header(j, &vhd->header);
1067 if (err)
1068 goto out;
1070 if (locs) {
1071 err = vhd_journal_restore_locators(j, locators, locs);
1072 if (err)
1073 goto out;
1076 err = vhd_journal_restore_bat(j, &vhd->bat);
1077 if (err)
1078 goto out;
1080 if (vhd_has_batmap(vhd)) {
1081 err = vhd_journal_restore_batmap(j, &vhd->batmap);
1082 if (err)
1083 goto out;
1086 err = 0;
1088 out:
1089 if (locators) {
1090 for (i = 0; i < locs; i++)
1091 free(locators[i]);
1092 free(locators);
1095 if (!err && !vhd->is_block)
1096 err = ftruncate(vhd->fd,
1097 j->header.vhd_footer_offset +
1098 sizeof(vhd_footer_t));
1100 return err;
1103 static int
1104 vhd_journal_disable_vhd(vhd_journal_t *j)
1106 int err;
1107 vhd_context_t *vhd;
1109 vhd = &j->vhd;
1111 err = vhd_get_footer(vhd);
1112 if (err)
1113 return err;
1115 memcpy(&vhd->footer.cookie,
1116 VHD_POISON_COOKIE, sizeof(vhd->footer.cookie));
1117 vhd->footer.checksum = vhd_checksum_footer(&vhd->footer);
1119 err = vhd_write_footer(vhd, &vhd->footer);
1120 if (err)
1121 return err;
1123 return 0;
1126 static int
1127 vhd_journal_enable_vhd(vhd_journal_t *j)
1129 int err;
1130 vhd_context_t *vhd;
1132 vhd = &j->vhd;
1134 err = vhd_get_footer(vhd);
1135 if (err)
1136 return err;
1138 if (!vhd_disabled(vhd))
1139 return 0;
1141 memcpy(&vhd->footer.cookie, HD_COOKIE, sizeof(vhd->footer.cookie));
1142 vhd->footer.checksum = vhd_checksum_footer(&vhd->footer);
1144 err = vhd_write_footer(vhd, &vhd->footer);
1145 if (err)
1146 return err;
1148 return 0;
1151 int
1152 vhd_journal_close(vhd_journal_t *j)
1154 if (j->jfd)
1155 close(j->jfd);
1157 vhd_close(&j->vhd);
1158 free(j->jname);
1160 return 0;
1163 int
1164 vhd_journal_remove(vhd_journal_t *j)
1166 int err;
1168 err = vhd_journal_enable_vhd(j);
1169 if (err)
1170 return err;
1172 if (j->jfd) {
1173 close(j->jfd);
1174 if (!j->is_block)
1175 unlink(j->jname);
1178 vhd_close(&j->vhd);
1179 free(j->jname);
1181 return 0;
1184 int
1185 vhd_journal_open(vhd_journal_t *j, const char *file, const char *jfile)
1187 int err;
1188 vhd_context_t *vhd;
1190 memset(j, 0, sizeof(vhd_journal_t));
1192 j->jfd = -1;
1193 vhd = &j->vhd;
1195 j->jname = strdup(jfile);
1196 if (j->jname == NULL)
1197 return -ENOMEM;
1199 j->jfd = open(j->jname, O_LARGEFILE | O_RDWR);
1200 if (j->jfd == -1) {
1201 err = -errno;
1202 goto fail;
1205 err = vhd_test_file_fixed(j->jname, &j->is_block);
1206 if (err)
1207 goto fail;
1209 vhd->fd = open(file, O_LARGEFILE | O_RDWR | O_DIRECT);
1210 if (vhd->fd == -1) {
1211 err = -errno;
1212 goto fail;
1215 err = vhd_test_file_fixed(file, &vhd->is_block);
1216 if (err)
1217 goto fail;
1219 err = vhd_journal_read_journal_header(j, &j->header);
1220 if (err)
1221 goto fail;
1223 err = vhd_journal_restore_metadata(j);
1224 if (err)
1225 goto fail;
1227 close(vhd->fd);
1228 free(vhd->bat.bat);
1229 free(vhd->batmap.map);
1231 err = vhd_open(vhd, file, VHD_OPEN_RDWR);
1232 if (err)
1233 goto fail;
1235 err = vhd_get_bat(vhd);
1236 if (err)
1237 goto fail;
1239 if (vhd_has_batmap(vhd)) {
1240 err = vhd_get_batmap(vhd);
1241 if (err)
1242 goto fail;
1245 err = vhd_journal_disable_vhd(j);
1246 if (err)
1247 goto fail;
1249 return 0;
1251 fail:
1252 vhd_journal_close(j);
1253 return err;
1256 int
1257 vhd_journal_create(vhd_journal_t *j, const char *file, const char *jfile)
1259 char *buf;
1260 int i, err;
1261 size_t size;
1262 off_t off;
1263 struct stat stats;
1265 memset(j, 0, sizeof(vhd_journal_t));
1266 j->jfd = -1;
1268 j->jname = strdup(jfile);
1269 if (j->jname == NULL) {
1270 err = -ENOMEM;
1271 goto fail1;
1274 if (access(j->jname, F_OK) == 0) {
1275 err = vhd_test_file_fixed(j->jname, &j->is_block);
1276 if (err)
1277 goto fail1;
1279 if (!j->is_block) {
1280 err = -EEXIST;
1281 goto fail1;
1285 if (j->is_block)
1286 j->jfd = open(j->jname, O_LARGEFILE | O_RDWR, 0644);
1287 else
1288 j->jfd = open(j->jname,
1289 O_CREAT | O_TRUNC | O_LARGEFILE | O_RDWR, 0644);
1290 if (j->jfd == -1) {
1291 err = -errno;
1292 goto fail1;
1295 err = vhd_open(&j->vhd, file, VHD_OPEN_RDWR | VHD_OPEN_STRICT);
1296 if (err)
1297 goto fail1;
1299 err = vhd_get_bat(&j->vhd);
1300 if (err)
1301 goto fail2;
1303 if (vhd_has_batmap(&j->vhd)) {
1304 err = vhd_get_batmap(&j->vhd);
1305 if (err)
1306 goto fail2;
1309 err = vhd_journal_add_journal_header(j);
1310 if (err)
1311 goto fail2;
1313 err = vhd_journal_add_metadata(j);
1314 if (err)
1315 goto fail2;
1317 err = vhd_journal_disable_vhd(j);
1318 if (err)
1319 goto fail2;
1321 err = vhd_journal_sync(j);
1322 if (err)
1323 goto fail2;
1325 return 0;
1327 fail1:
1328 if (j->jfd != -1) {
1329 close(j->jfd);
1330 if (!j->is_block)
1331 unlink(j->jname);
1333 free(j->jname);
1334 memset(j, 0, sizeof(vhd_journal_t));
1336 return err;
1338 fail2:
1339 vhd_journal_remove(j);
1340 return err;
1343 int
1344 vhd_journal_add_block(vhd_journal_t *j, uint32_t block, char mode)
1346 int err;
1347 char *buf;
1348 off_t off;
1349 size_t size;
1350 uint64_t blk;
1351 vhd_context_t *vhd;
1353 buf = NULL;
1354 vhd = &j->vhd;
1356 if (!vhd_type_dynamic(vhd))
1357 return -EINVAL;
1359 err = vhd_get_bat(vhd);
1360 if (err)
1361 return err;
1363 if (block >= vhd->bat.entries)
1364 return -ERANGE;
1366 blk = vhd->bat.bat[block];
1367 if (blk == DD_BLK_UNUSED)
1368 return 0;
1370 off = vhd_sectors_to_bytes(blk);
1372 if (mode & VHD_JOURNAL_METADATA) {
1373 size = vhd_sectors_to_bytes(vhd->bm_secs);
1375 err = vhd_read_bitmap(vhd, block, &buf);
1376 if (err)
1377 return err;
1379 err = vhd_journal_update(j, off, buf, size,
1380 VHD_JOURNAL_ENTRY_TYPE_DATA);
1382 free(buf);
1384 if (err)
1385 return err;
1388 if (mode & VHD_JOURNAL_DATA) {
1389 off += vhd_sectors_to_bytes(vhd->bm_secs);
1390 size = vhd_sectors_to_bytes(vhd->spb);
1392 err = vhd_read_block(vhd, block, &buf);
1393 if (err)
1394 return err;
1396 err = vhd_journal_update(j, off, buf, size,
1397 VHD_JOURNAL_ENTRY_TYPE_DATA);
1398 free(buf);
1400 if (err)
1401 return err;
1404 return vhd_journal_sync(j);
1407 /*
1408 * commit indicates the transaction completed
1409 * successfully and we can remove the undo log
1410 */
1411 int
1412 vhd_journal_commit(vhd_journal_t *j)
1414 int err;
1416 j->header.journal_data_entries = 0;
1417 j->header.journal_metadata_entries = 0;
1418 j->header.journal_data_offset = 0;
1419 j->header.journal_metadata_offset = 0;
1421 err = vhd_journal_write_header(j, &j->header);
1422 if (err)
1423 return err;
1425 if (!j->is_block)
1426 err = vhd_journal_truncate(j, sizeof(vhd_journal_header_t));
1427 if (err)
1428 return -errno;
1430 return 0;
1433 /*
1434 * revert indicates the transaction failed
1435 * and we should revert any changes via the undo log
1436 */
1437 int
1438 vhd_journal_revert(vhd_journal_t *j)
1440 int i, err;
1441 char *buf, *file;
1442 vhd_context_t *vhd;
1443 vhd_journal_entry_t entry;
1445 err = 0;
1446 vhd = &j->vhd;
1447 buf = NULL;
1449 file = strdup(vhd->file);
1450 if (!file)
1451 return -ENOMEM;
1453 vhd_close(&j->vhd);
1454 j->vhd.fd = open(file, O_RDWR | O_DIRECT | O_LARGEFILE);
1455 if (j->vhd.fd == -1) {
1456 free(file);
1457 return -errno;
1460 err = vhd_test_file_fixed(file, &vhd->is_block);
1461 if (err) {
1462 free(file);
1463 return err;
1466 err = vhd_journal_restore_metadata(j);
1467 if (err) {
1468 free(file);
1469 return err;
1472 close(vhd->fd);
1473 free(vhd->bat.bat);
1474 free(vhd->batmap.map);
1476 err = vhd_open(vhd, file, VHD_OPEN_RDWR);
1477 free(file);
1478 if (err)
1479 return err;
1481 err = vhd_journal_seek(j, j->header.journal_data_offset, SEEK_SET);
1482 if (err)
1483 return err;
1485 for (i = 0; i < j->header.journal_data_entries; i++) {
1486 err = vhd_journal_read_entry(j, &entry);
1487 if (err)
1488 goto end;
1490 err = posix_memalign((void **)&buf,
1491 VHD_SECTOR_SIZE, entry.size);
1492 if (err) {
1493 err = -err;
1494 buf = NULL;
1495 goto end;
1498 err = vhd_journal_read(j, buf, entry.size);
1499 if (err)
1500 goto end;
1502 err = vhd_journal_validate_entry_data(&entry, buf);
1503 if (err)
1504 goto end;
1506 err = vhd_seek(vhd, entry.offset, SEEK_SET);
1507 if (err)
1508 goto end;
1510 err = vhd_write(vhd, buf, entry.size);
1511 if (err)
1512 goto end;
1514 err = 0;
1516 end:
1517 free(buf);
1518 buf = NULL;
1519 if (err)
1520 break;
1523 if (err)
1524 return err;
1526 if (!vhd->is_block) {
1527 err = ftruncate(vhd->fd, j->header.vhd_footer_offset +
1528 sizeof(vhd_footer_t));
1529 if (err)
1530 return -errno;
1533 return vhd_journal_sync(j);