static int vhd_journal_write_header(vhd_journal_t *j, vhd_journal_header_t *header) { int err; size_t size; vhd_journal_header_t h; memcpy(&h, header, sizeof(vhd_journal_header_t)); err = vhd_journal_validate_header(j, &h); if (err) return err; vhd_journal_header_out(&h); size = sizeof(vhd_journal_header_t); err = vhd_journal_seek(j, 0, SEEK_SET); if (err) return err; err = vhd_journal_write(j, &h, size); if (err) return err; return 0; }
static int vhd_journal_validate_header(vhd_journal_t *j, vhd_journal_header_t *header) { int err; off64_t eof; if (memcmp(header->cookie, VHD_JOURNAL_HEADER_COOKIE, sizeof(header->cookie))) return -EINVAL; err = vhd_journal_seek(j, j->header.journal_eof, SEEK_SET); if (err) return err; eof = vhd_journal_position(j); if (eof == (off64_t)-1) return -errno; if (j->header.journal_data_offset > j->header.journal_eof) return -EINVAL; if (j->header.journal_metadata_offset > j->header.journal_eof) return -EINVAL; return 0; }
static int vhd_journal_update(vhd_journal_t *j, off_t offset, char *buf, size_t size, uint32_t type) { int err; off_t eof; uint64_t *off, off_bak; uint32_t *entries; vhd_journal_entry_t entry; entry.type = type; entry.size = size; entry.offset = offset; entry.cookie = VHD_JOURNAL_ENTRY_COOKIE; entry.checksum = vhd_journal_checksum_entry(&entry, buf, size); err = vhd_journal_seek(j, j->header.journal_eof, SEEK_SET); if (err) return err; err = vhd_journal_write_entry(j, &entry); if (err) goto fail; err = vhd_journal_write(j, buf, size); if (err) goto fail; if (type == VHD_JOURNAL_ENTRY_TYPE_DATA) { off = &j->header.journal_data_offset; entries = &j->header.journal_data_entries; } else { off = &j->header.journal_metadata_offset; entries = &j->header.journal_metadata_entries; } off_bak = *off; if (!(*entries)++) *off = j->header.journal_eof; j->header.journal_eof += (size + sizeof(vhd_journal_entry_t)); err = vhd_journal_write_header(j, &j->header); if (err) { if (!--(*entries)) *off = off_bak; j->header.journal_eof -= (size + sizeof(vhd_journal_entry_t)); goto fail; } return 0; fail: if (!j->is_block) vhd_journal_truncate(j, j->header.journal_eof); return err; }
static int vhd_journal_read_journal_header(vhd_journal_t *j, vhd_journal_header_t *header) { int err; size_t size; size = sizeof(vhd_journal_header_t); err = vhd_journal_seek(j, 0, SEEK_SET); if (err) return err; err = vhd_journal_read(j, header, size); if (err) return err; vhd_journal_header_in(header); return vhd_journal_validate_header(j, header); }
static int vhd_journal_restore_metadata(vhd_journal_t *j) { off64_t off; char **locators; vhd_footer_t copy; vhd_context_t *vhd; int i, locs, hlocs, err; vhd = &j->vhd; locs = 0; hlocs = 0; locators = NULL; err = vhd_journal_seek(j, sizeof(vhd_journal_header_t), SEEK_SET); if (err) return err; err = vhd_journal_read_footer(j, &vhd->footer); if (err) return err; if (!vhd_type_dynamic(vhd)) goto restore; err = vhd_journal_read_footer_copy(j, ©); if (err) return err; err = vhd_journal_read_header(j, &vhd->header); if (err) return err; for (hlocs = 0, i = 0; i < vhd_parent_locator_count(vhd); i++) { if (vhd_validate_platform_code(vhd->header.loc[i].code)) return err; if (vhd->header.loc[i].code != PLAT_CODE_NONE) hlocs++; } if (hlocs) { err = vhd_journal_read_locators(j, &locators, &locs); if (err) return err; if (hlocs != locs) { err = -EINVAL; goto out; } } err = vhd_journal_read_bat(j, &vhd->bat); if (err) goto out; if (vhd_has_batmap(vhd)) { err = vhd_journal_read_batmap(j, &vhd->batmap); if (err) goto out; } restore: off = vhd_journal_position(j); if (off == (off64_t)-1) return -errno; if (j->header.journal_data_offset != off) return -EINVAL; err = vhd_journal_restore_footer(j, &vhd->footer); if (err) goto out; if (!vhd_type_dynamic(vhd)) goto out; err = vhd_journal_restore_footer_copy(j, ©); if (err) goto out; err = vhd_journal_restore_header(j, &vhd->header); if (err) goto out; if (locs) { err = vhd_journal_restore_locators(j, locators, locs); if (err) goto out; } err = vhd_journal_restore_bat(j, &vhd->bat); if (err) goto out; if (vhd_has_batmap(vhd)) { err = vhd_journal_restore_batmap(j, &vhd->batmap); if (err) goto out; } err = 0; out: if (locators) { for (i = 0; i < locs; i++) free(locators[i]); free(locators); } if (!err && !vhd->is_block) err = ftruncate(vhd->fd, j->header.vhd_footer_offset + sizeof(vhd_footer_t)); return err; }
static int vhd_journal_read_locators(vhd_journal_t *j, char ***locators, int *locs) { int err, n, _locs; char **_locators; void *buf; off_t pos; vhd_journal_entry_t entry; _locs = 0; *locs = 0; *locators = NULL; n = sizeof(j->vhd.header.loc) / sizeof(vhd_parent_locator_t); _locators = calloc(n, sizeof(char *)); if (!_locators) return -ENOMEM; for (;;) { buf = NULL; pos = vhd_journal_position(j); err = vhd_journal_read_entry(j, &entry); if (err) goto fail; if (entry.type != VHD_JOURNAL_ENTRY_TYPE_LOCATOR) { err = vhd_journal_seek(j, pos, SEEK_SET); if (err) goto fail; break; } if (_locs >= n) { err = -EINVAL; goto fail; } err = posix_memalign(&buf, VHD_SECTOR_SIZE, entry.size); if (err) { err = -err; buf = NULL; goto fail; } err = vhd_journal_read(j, buf, entry.size); if (err) goto fail; _locators[_locs++] = buf; err = 0; } *locs = _locs; *locators = _locators; return 0; fail: if (_locators) { for (n = 0; n < _locs; n++) free(_locators[n]); free(_locators); } return err; }
/* * revert indicates the transaction failed * and we should revert any changes via the undo log */ int vhd_journal_revert(vhd_journal_t *j) { int i, err; char *file; void *buf; vhd_context_t *vhd; vhd_journal_entry_t entry; err = 0; vhd = &j->vhd; buf = NULL; file = strdup(vhd->file); if (!file) return -ENOMEM; vhd_close(&j->vhd); j->vhd.fd = open(file, O_RDWR | O_DIRECT | O_LARGEFILE); if (j->vhd.fd == -1) { free(file); return -errno; } err = vhd_test_file_fixed(file, &vhd->is_block); if (err) { free(file); return err; } err = vhd_journal_restore_metadata(j); if (err) { free(file); return err; } close(vhd->fd); free(vhd->bat.bat); free(vhd->batmap.map); err = vhd_open(vhd, file, VHD_OPEN_RDWR); free(file); if (err) return err; err = vhd_journal_seek(j, j->header.journal_data_offset, SEEK_SET); if (err) return err; for (i = 0; i < j->header.journal_data_entries; i++) { err = vhd_journal_read_entry(j, &entry); if (err) goto end; err = posix_memalign(&buf, VHD_SECTOR_SIZE, entry.size); if (err) { err = -err; buf = NULL; goto end; } err = vhd_journal_read(j, buf, entry.size); if (err) goto end; err = vhd_journal_validate_entry_data(&entry, buf); if (err) goto end; err = vhd_seek(vhd, entry.offset, SEEK_SET); if (err) goto end; err = vhd_write(vhd, buf, entry.size); if (err) goto end; err = 0; end: free(buf); buf = NULL; if (err) break; } if (err) return err; if (!vhd->is_block) { err = ftruncate(vhd->fd, j->header.vhd_footer_offset + sizeof(vhd_footer_t)); if (err) return -errno; } return vhd_journal_sync(j); }