?? libvhd-journal.c
字號:
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "atomicio.h"
#include "libvhd-journal.h"
#define VHD_JOURNAL_ENTRY_TYPE_FOOTER_P 1
#define VHD_JOURNAL_ENTRY_TYPE_FOOTER_C 2
#define VHD_JOURNAL_ENTRY_TYPE_HEADER 3
#define VHD_JOURNAL_ENTRY_TYPE_LOCATOR 4
#define VHD_JOURNAL_ENTRY_TYPE_BAT 5
#define VHD_JOURNAL_ENTRY_TYPE_BATMAP_H 6
#define VHD_JOURNAL_ENTRY_TYPE_BATMAP_M 7
#define VHD_JOURNAL_ENTRY_TYPE_DATA 8
typedef struct vhd_journal_entry {
uint64_t cookie;
uint32_t type;
uint32_t size;
uint64_t offset;
uint32_t checksum;
} vhd_journal_entry_t;
static inline int
vhd_journal_seek(vhd_journal_t *j, off64_t offset, int whence)
{
off64_t off;
off = lseek64(j->jfd, offset, whence);
if (off == (off64_t)-1)
return -errno;
return 0;
}
static inline off64_t
vhd_journal_position(vhd_journal_t *j)
{
return lseek64(j->jfd, 0, SEEK_CUR);
}
static inline int
vhd_journal_read(vhd_journal_t *j, void *buf, size_t size)
{
ssize_t ret;
errno = 0;
ret = atomicio(read, j->jfd, buf, size);
if (ret != size)
return (errno ? -errno : -EIO);
return 0;
}
static inline int
vhd_journal_write(vhd_journal_t *j, void *buf, size_t size)
{
ssize_t ret;
errno = 0;
ret = atomicio(vwrite, j->jfd, buf, size);
if (ret != size)
return (errno ? -errno : -EIO);
return 0;
}
static inline int
vhd_journal_truncate(vhd_journal_t *j, off64_t length)
{
int err;
err = ftruncate(j->jfd, length);
if (err == -1)
return -errno;
return 0;
}
static inline int
vhd_journal_sync(vhd_journal_t *j)
{
int err;
err = fdatasync(j->jfd);
if (err)
return -errno;
return 0;
}
static inline void
vhd_journal_header_in(vhd_journal_header_t *header)
{
BE64_IN(&header->vhd_footer_offset);
BE32_IN(&header->journal_data_entries);
BE32_IN(&header->journal_metadata_entries);
BE64_IN(&header->journal_data_offset);
BE64_IN(&header->journal_metadata_offset);
}
static inline void
vhd_journal_header_out(vhd_journal_header_t *header)
{
BE64_OUT(&header->vhd_footer_offset);
BE32_OUT(&header->journal_data_entries);
BE32_OUT(&header->journal_metadata_entries);
BE64_OUT(&header->journal_data_offset);
BE64_OUT(&header->journal_metadata_offset);
}
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_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_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_add_journal_header(vhd_journal_t *j)
{
int err;
off64_t off;
vhd_context_t *vhd;
vhd = &j->vhd;
memset(&j->header, 0, sizeof(vhd_journal_header_t));
err = vhd_seek(vhd, 0, SEEK_END);
if (err)
return err;
off = vhd_position(vhd);
if (off == (off64_t)-1)
return -errno;
err = vhd_get_footer(vhd);
if (err)
return err;
uuid_copy(j->header.uuid, vhd->footer.uuid);
memcpy(j->header.cookie,
VHD_JOURNAL_HEADER_COOKIE, sizeof(j->header.cookie));
j->header.vhd_footer_offset = off - sizeof(vhd_footer_t);
j->header.journal_eof = sizeof(vhd_journal_header_t);
return vhd_journal_write_header(j, &j->header);
}
static void
vhd_journal_entry_in(vhd_journal_entry_t *entry)
{
BE32_IN(&entry->type);
BE32_IN(&entry->size);
BE64_IN(&entry->offset);
BE64_IN(&entry->cookie);
BE32_IN(&entry->checksum);
}
static void
vhd_journal_entry_out(vhd_journal_entry_t *entry)
{
BE32_OUT(&entry->type);
BE32_OUT(&entry->size);
BE64_OUT(&entry->offset);
BE64_OUT(&entry->cookie);
BE32_OUT(&entry->checksum);
}
static uint32_t
vhd_journal_checksum_entry(vhd_journal_entry_t *entry, char *buf, size_t size)
{
int i;
unsigned char *blob;
uint32_t checksum, tmp;
checksum = 0;
tmp = entry->checksum;
entry->checksum = 0;
blob = (unsigned char *)entry;
for (i = 0; i < sizeof(vhd_journal_entry_t); i++)
checksum += blob[i];
blob = (unsigned char *)buf;
for (i = 0; i < size; i++)
checksum += blob[i];
entry->checksum = tmp;
return ~checksum;
}
static int
vhd_journal_validate_entry(vhd_journal_entry_t *entry)
{
if (entry->size == 0)
return -EINVAL;
if (entry->size & (VHD_SECTOR_SIZE - 1))
return -EINVAL;
if (entry->cookie != VHD_JOURNAL_ENTRY_COOKIE)
return -EINVAL;
return 0;
}
static int
vhd_journal_read_entry(vhd_journal_t *j, vhd_journal_entry_t *entry)
{
int err;
err = vhd_journal_read(j, entry, sizeof(vhd_journal_entry_t));
if (err)
return err;
vhd_journal_entry_in(entry);
return vhd_journal_validate_entry(entry);
}
static int
vhd_journal_write_entry(vhd_journal_t *j, vhd_journal_entry_t *entry)
{
int err;
vhd_journal_entry_t e;
err = vhd_journal_validate_entry(entry);
if (err)
return err;
memcpy(&e, entry, sizeof(vhd_journal_entry_t));
vhd_journal_entry_out(&e);
err = vhd_journal_write(j, &e, sizeof(vhd_journal_entry_t));
if (err)
err;
return 0;
}
static int
vhd_journal_validate_entry_data(vhd_journal_entry_t *entry, char *buf)
{
int err;
uint32_t checksum;
err = 0;
checksum = vhd_journal_checksum_entry(entry, buf, entry->size);
if (checksum != entry->checksum)
return -EINVAL;
return err;
}
static int
vhd_journal_update(vhd_journal_t *j, off64_t offset,
char *buf, size_t size, uint32_t type)
{
int err;
off64_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_add_footer(vhd_journal_t *j)
{
int err;
off64_t off;
vhd_context_t *vhd;
vhd_footer_t footer;
vhd = &j->vhd;
err = vhd_seek(vhd, 0, SEEK_END);
if (err)
return err;
off = vhd_position(vhd);
if (off == (off64_t)-1)
return -errno;
err = vhd_read_footer_at(vhd, &footer, off - sizeof(vhd_footer_t));
if (err)
return err;
vhd_footer_out(&footer);
err = vhd_journal_update(j, off - sizeof(vhd_footer_t),
(char *)&footer,
sizeof(vhd_footer_t),
VHD_JOURNAL_ENTRY_TYPE_FOOTER_P);
if (err)
return err;
if (!vhd_type_dynamic(vhd))
return 0;
err = vhd_read_footer_at(vhd, &footer, 0);
if (err)
return err;
vhd_footer_out(&footer);
err = vhd_journal_update(j, 0,
(char *)&footer,
sizeof(vhd_footer_t),
VHD_JOURNAL_ENTRY_TYPE_FOOTER_C);
return err;
}
static int
vhd_journal_add_header(vhd_journal_t *j)
{
int err;
off64_t off;
vhd_context_t *vhd;
vhd_header_t header;
vhd = &j->vhd;
err = vhd_read_header(vhd, &header);
if (err)
return err;
off = vhd->footer.data_offset;
vhd_header_out(&header);
err = vhd_journal_update(j, off,
(char *)&header,
sizeof(vhd_header_t),
VHD_JOURNAL_ENTRY_TYPE_HEADER);
return err;
}
static int
vhd_journal_add_locators(vhd_journal_t *j)
{
int i, n, err;
vhd_context_t *vhd;
vhd = &j->vhd;
err = vhd_get_header(vhd);
if (err)
return err;
n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t);
for (i = 0; i < n; i++) {
char *buf;
off64_t off;
size_t size;
vhd_parent_locator_t *loc;
loc = vhd->header.loc + i;
err = vhd_validate_platform_code(loc->code);
if (err)
return err;
if (loc->code == PLAT_CODE_NONE)
continue;
off = loc->data_offset;
size = vhd_parent_locator_size(loc);
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
if (err)
return -err;
err = vhd_seek(vhd, off, SEEK_SET);
if (err)
goto end;
err = vhd_read(vhd, buf, size);
if (err)
goto end;
err = vhd_journal_update(j, off, buf, size,
VHD_JOURNAL_ENTRY_TYPE_LOCATOR);
if (err)
goto end;
err = 0;
end:
free(buf);
if (err)
break;
}
return err;
}
static int
vhd_journal_add_bat(vhd_journal_t *j)
{
int err;
off64_t off;
size_t size;
vhd_bat_t bat;
vhd_context_t *vhd;
vhd = &j->vhd;
err = vhd_get_header(vhd);
if (err)
return err;
err = vhd_read_bat(vhd, &bat);
if (err)
return err;
off = vhd->header.table_offset;
size = vhd_bytes_padded(bat.entries * sizeof(uint32_t));
vhd_bat_out(&bat);
err = vhd_journal_update(j, off, (char *)bat.bat, size,
VHD_JOURNAL_ENTRY_TYPE_BAT);
free(bat.bat);
return err;
}
static int
vhd_journal_add_batmap(vhd_journal_t *j)
{
int err;
off64_t off;
size_t size;
vhd_context_t *vhd;
vhd_batmap_t batmap;
vhd = &j->vhd;
err = vhd_batmap_header_offset(vhd, &off);
if (err)
return err;
err = vhd_read_batmap(vhd, &batmap);
if (err)
return err;
size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr));
vhd_batmap_header_out(&batmap);
err = vhd_journal_update(j, off, (char *)&batmap.header, size,
VHD_JOURNAL_ENTRY_TYPE_BATMAP_H);
if (err)
goto out;
vhd_batmap_header_in(&batmap);
off = batmap.header.batmap_offset;
size = vhd_sectors_to_bytes(batmap.header.batmap_size);
err = vhd_journal_update(j, off, batmap.map, size,
VHD_JOURNAL_ENTRY_TYPE_BATMAP_M);
out:
free(batmap.map);
return err;
}
static int
vhd_journal_add_metadata(vhd_journal_t *j)
{
int err;
off64_t eof;
vhd_context_t *vhd;
vhd = &j->vhd;
err = vhd_journal_add_footer(j);
if (err)
return err;
if (!vhd_type_dynamic(vhd))
return 0;
err = vhd_journal_add_header(j);
if (err)
return err;
err = vhd_journal_add_locators(j);
if (err)
return err;
err = vhd_journal_add_bat(j);
if (err)
return err;
if (vhd_has_batmap(vhd)) {
err = vhd_journal_add_batmap(j);
if (err)
return err;
}
j->header.journal_data_offset = j->header.journal_eof;
return vhd_journal_write_header(j, &j->header);
}
static int
__vhd_journal_read_footer(vhd_journal_t *j,
vhd_footer_t *footer, uint32_t type)
{
int err;
vhd_journal_entry_t entry;
err = vhd_journal_read_entry(j, &entry);
if (err)
return err;
if (entry.type != type)
return -EINVAL;
if (entry.size != sizeof(vhd_footer_t))
return -EINVAL;
err = vhd_journal_read(j, footer, entry.size);
if (err)
return err;
vhd_footer_in(footer);
return vhd_validate_footer(footer);
}
static int
vhd_journal_read_footer(vhd_journal_t *j, vhd_footer_t *footer)
{
return __vhd_journal_read_footer(j, footer,
VHD_JOURNAL_ENTRY_TYPE_FOOTER_P);
}
static int
vhd_journal_read_footer_copy(vhd_journal_t *j, vhd_footer_t *footer)
{
return __vhd_journal_read_footer(j, footer,
VHD_JOURNAL_ENTRY_TYPE_FOOTER_C);
}
static int
vhd_journal_read_header(vhd_journal_t *j, vhd_header_t *header)
{
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_HEADER)
return -EINVAL;
if (entry.size != sizeof(vhd_header_t))
return -EINVAL;
err = vhd_journal_read(j, header, entry.size);
if (err)
return err;
vhd_header_in(header);
return vhd_validate_header(header);
}
static int
vhd_journal_read_locators(vhd_journal_t *j, char ***locators, int *locs)
{
int err, n, _locs;
char **_locators, *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((void **)&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;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -