?? libvhd-journal.c
字號:
fail:
if (_locators) {
for (n = 0; n < _locs; n++)
free(_locators[n]);
free(_locators);
}
return err;
}
static int
vhd_journal_read_bat(vhd_journal_t *j, vhd_bat_t *bat)
{
int err;
size_t size;
vhd_context_t *vhd;
vhd_journal_entry_t entry;
vhd = &j->vhd;
size = vhd_bytes_padded(vhd->header.max_bat_size * sizeof(uint32_t));
err = vhd_journal_read_entry(j, &entry);
if (err)
return err;
if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BAT)
return -EINVAL;
if (entry.size != size)
return -EINVAL;
if (entry.offset != vhd->header.table_offset)
return -EINVAL;
err = posix_memalign((void **)&bat->bat, VHD_SECTOR_SIZE, size);
if (err)
return -err;
err = vhd_journal_read(j, bat->bat, entry.size);
if (err)
goto fail;
bat->spb = vhd->header.block_size >> VHD_SECTOR_SHIFT;
bat->entries = vhd->header.max_bat_size;
vhd_bat_in(bat);
return 0;
fail:
free(bat->bat);
bat->bat = NULL;
return err;
}
static int
vhd_journal_read_batmap_header(vhd_journal_t *j, vhd_batmap_t *batmap)
{
int err;
char *buf;
size_t size;
vhd_journal_entry_t entry;
size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr));
err = vhd_journal_read_entry(j, &entry);
if (err)
return err;
if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BATMAP_H)
return -EINVAL;
if (entry.size != size)
return -EINVAL;
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
if (err)
return err;
err = vhd_journal_read(j, buf, entry.size);
if (err) {
free(buf);
return err;
}
memcpy(&batmap->header, buf, sizeof(batmap->header));
vhd_batmap_header_in(batmap);
return vhd_validate_batmap_header(batmap);
}
static int
vhd_journal_read_batmap_map(vhd_journal_t *j, vhd_batmap_t *batmap)
{
int err;
vhd_journal_entry_t entry;
err = vhd_journal_read_entry(j, &entry);
if (err)
return err;
if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BATMAP_M)
return -EINVAL;
if (entry.size != vhd_sectors_to_bytes(batmap->header.batmap_size))
return -EINVAL;
if (entry.offset != batmap->header.batmap_offset)
return -EINVAL;
err = posix_memalign((void **)&batmap->map,
VHD_SECTOR_SIZE, entry.size);
if (err)
return -err;
err = vhd_journal_read(j, batmap->map, entry.size);
if (err) {
free(batmap->map);
batmap->map = NULL;
return err;
}
return 0;
}
static int
vhd_journal_read_batmap(vhd_journal_t *j, vhd_batmap_t *batmap)
{
int err;
err = vhd_journal_read_batmap_header(j, batmap);
if (err)
return err;
err = vhd_journal_read_batmap_map(j, batmap);
if (err)
return err;
err = vhd_validate_batmap(batmap);
if (err) {
free(batmap->map);
batmap->map = NULL;
return err;
}
return 0;
}
static int
vhd_journal_restore_footer(vhd_journal_t *j, vhd_footer_t *footer)
{
return vhd_write_footer_at(&j->vhd, footer,
j->header.vhd_footer_offset);
}
static int
vhd_journal_restore_footer_copy(vhd_journal_t *j, vhd_footer_t *footer)
{
return vhd_write_footer_at(&j->vhd, footer, 0);
}
static int
vhd_journal_restore_header(vhd_journal_t *j, vhd_header_t *header)
{
off64_t off;
vhd_context_t *vhd;
vhd = &j->vhd;
off = vhd->footer.data_offset;
return vhd_write_header_at(&j->vhd, header, off);
}
static int
vhd_journal_restore_locators(vhd_journal_t *j, char **locators, int locs)
{
size_t size;
vhd_context_t *vhd;
int i, n, lidx, err;
vhd_parent_locator_t *loc;
lidx = 0;
vhd = &j->vhd;
n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t);
for (i = 0; i < n && lidx < locs; i++) {
loc = vhd->header.loc + i;
if (loc->code == PLAT_CODE_NONE)
continue;
err = vhd_seek(vhd, loc->data_offset, SEEK_SET);
if (err)
return err;
size = vhd_parent_locator_size(loc);
err = vhd_write(vhd, locators[lidx++], size);
if (err)
return err;
}
return 0;
}
static int
vhd_journal_restore_bat(vhd_journal_t *j, vhd_bat_t *bat)
{
return vhd_write_bat(&j->vhd, bat);
}
static int
vhd_journal_restore_batmap(vhd_journal_t *j, vhd_batmap_t *batmap)
{
return vhd_write_batmap(&j->vhd, batmap);
}
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_disable_vhd(vhd_journal_t *j)
{
int err;
vhd_context_t *vhd;
vhd = &j->vhd;
err = vhd_get_footer(vhd);
if (err)
return err;
memcpy(&vhd->footer.cookie,
VHD_POISON_COOKIE, sizeof(vhd->footer.cookie));
vhd->footer.checksum = vhd_checksum_footer(&vhd->footer);
err = vhd_write_footer(vhd, &vhd->footer);
if (err)
return err;
return 0;
}
static int
vhd_journal_enable_vhd(vhd_journal_t *j)
{
int err;
vhd_context_t *vhd;
vhd = &j->vhd;
err = vhd_get_footer(vhd);
if (err)
return err;
if (!vhd_disabled(vhd))
return 0;
memcpy(&vhd->footer.cookie, HD_COOKIE, sizeof(vhd->footer.cookie));
vhd->footer.checksum = vhd_checksum_footer(&vhd->footer);
err = vhd_write_footer(vhd, &vhd->footer);
if (err)
return err;
return 0;
}
int
vhd_journal_close(vhd_journal_t *j)
{
if (j->jfd)
close(j->jfd);
vhd_close(&j->vhd);
free(j->jname);
return 0;
}
int
vhd_journal_remove(vhd_journal_t *j)
{
int err;
err = vhd_journal_enable_vhd(j);
if (err)
return err;
if (j->jfd) {
close(j->jfd);
if (!j->is_block)
unlink(j->jname);
}
vhd_close(&j->vhd);
free(j->jname);
return 0;
}
int
vhd_journal_open(vhd_journal_t *j, const char *file, const char *jfile)
{
int err;
vhd_context_t *vhd;
memset(j, 0, sizeof(vhd_journal_t));
j->jfd = -1;
vhd = &j->vhd;
j->jname = strdup(jfile);
if (j->jname == NULL)
return -ENOMEM;
j->jfd = open(j->jname, O_LARGEFILE | O_RDWR);
if (j->jfd == -1) {
err = -errno;
goto fail;
}
err = vhd_test_file_fixed(j->jname, &j->is_block);
if (err)
goto fail;
vhd->fd = open(file, O_LARGEFILE | O_RDWR | O_DIRECT);
if (vhd->fd == -1) {
err = -errno;
goto fail;
}
err = vhd_test_file_fixed(file, &vhd->is_block);
if (err)
goto fail;
err = vhd_journal_read_journal_header(j, &j->header);
if (err)
goto fail;
err = vhd_journal_restore_metadata(j);
if (err)
goto fail;
close(vhd->fd);
free(vhd->bat.bat);
free(vhd->batmap.map);
err = vhd_open(vhd, file, VHD_OPEN_RDWR);
if (err)
goto fail;
err = vhd_get_bat(vhd);
if (err)
goto fail;
if (vhd_has_batmap(vhd)) {
err = vhd_get_batmap(vhd);
if (err)
goto fail;
}
err = vhd_journal_disable_vhd(j);
if (err)
goto fail;
return 0;
fail:
vhd_journal_close(j);
return err;
}
int
vhd_journal_create(vhd_journal_t *j, const char *file, const char *jfile)
{
char *buf;
int i, err;
size_t size;
off64_t off;
struct stat stats;
memset(j, 0, sizeof(vhd_journal_t));
j->jfd = -1;
j->jname = strdup(jfile);
if (j->jname == NULL) {
err = -ENOMEM;
goto fail1;
}
if (access(j->jname, F_OK) == 0) {
err = vhd_test_file_fixed(j->jname, &j->is_block);
if (err)
goto fail1;
if (!j->is_block) {
err = -EEXIST;
goto fail1;
}
}
if (j->is_block)
j->jfd = open(j->jname, O_LARGEFILE | O_RDWR, 0644);
else
j->jfd = open(j->jname,
O_CREAT | O_TRUNC | O_LARGEFILE | O_RDWR, 0644);
if (j->jfd == -1) {
err = -errno;
goto fail1;
}
err = vhd_open(&j->vhd, file, VHD_OPEN_RDWR | VHD_OPEN_STRICT);
if (err)
goto fail1;
err = vhd_get_bat(&j->vhd);
if (err)
goto fail2;
if (vhd_has_batmap(&j->vhd)) {
err = vhd_get_batmap(&j->vhd);
if (err)
goto fail2;
}
err = vhd_journal_add_journal_header(j);
if (err)
goto fail2;
err = vhd_journal_add_metadata(j);
if (err)
goto fail2;
err = vhd_journal_disable_vhd(j);
if (err)
goto fail2;
err = vhd_journal_sync(j);
if (err)
goto fail2;
return 0;
fail1:
if (j->jfd != -1) {
close(j->jfd);
if (!j->is_block)
unlink(j->jname);
}
free(j->jname);
memset(j, 0, sizeof(vhd_journal_t));
return err;
fail2:
vhd_journal_remove(j);
return err;
}
int
vhd_journal_add_block(vhd_journal_t *j, uint32_t block, char mode)
{
int err;
char *buf;
off64_t off;
size_t size;
uint64_t blk;
vhd_context_t *vhd;
buf = NULL;
vhd = &j->vhd;
if (!vhd_type_dynamic(vhd))
return -EINVAL;
err = vhd_get_bat(vhd);
if (err)
return err;
if (block >= vhd->bat.entries)
return -ERANGE;
blk = vhd->bat.bat[block];
if (blk == DD_BLK_UNUSED)
return 0;
off = vhd_sectors_to_bytes(blk);
if (mode & VHD_JOURNAL_METADATA) {
size = vhd_sectors_to_bytes(vhd->bm_secs);
err = vhd_read_bitmap(vhd, block, &buf);
if (err)
return err;
err = vhd_journal_update(j, off, buf, size,
VHD_JOURNAL_ENTRY_TYPE_DATA);
free(buf);
if (err)
return err;
}
if (mode & VHD_JOURNAL_DATA) {
off += vhd_sectors_to_bytes(vhd->bm_secs);
size = vhd_sectors_to_bytes(vhd->spb);
err = vhd_read_block(vhd, block, &buf);
if (err)
return err;
err = vhd_journal_update(j, off, buf, size,
VHD_JOURNAL_ENTRY_TYPE_DATA);
free(buf);
if (err)
return err;
}
return vhd_journal_sync(j);
}
/*
* commit indicates the transaction completed
* successfully and we can remove the undo log
*/
int
vhd_journal_commit(vhd_journal_t *j)
{
int err;
j->header.journal_data_entries = 0;
j->header.journal_metadata_entries = 0;
j->header.journal_data_offset = 0;
j->header.journal_metadata_offset = 0;
err = vhd_journal_write_header(j, &j->header);
if (err)
return err;
if (!j->is_block)
err = vhd_journal_truncate(j, sizeof(vhd_journal_header_t));
if (err)
return -errno;
return 0;
}
/*
* 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 *buf, *file;
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((void **)&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);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -