In vhd_write(), construct the footer and write it out. Next in line

is the dynamic header. After that, the block allocation table and
the actual blocks. It's for the blocks we need some infrastructure
support, because each data block is preceeded by a bitmap that tells
whether a sector in that block has been written, etc. The point is
that we interleave metadata with data and we don't have good support
functions for writing chunks of the image yet.
This commit is contained in:
marcel 2014-06-26 15:25:42 +00:00
parent 363855dd1b
commit 9cadcaea47

78
vhd.c
View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <uuid.h>
@ -51,7 +52,8 @@ __FBSDID("$FreeBSD$");
* o The timestamp is seconds since 1/1/2000 12:00:00 AM UTC
*/
#define VHD_BLOCK_SIZE 4096 /* 2MB blocks */
#define VHD_BLOCK_SIZE 4096 /* In sectors; 2MB blocks */
#define VHD_SECTOR_SIZE 512
struct vhd_footer {
char cookie[8];
@ -64,7 +66,7 @@ struct vhd_footer {
#define VHD_VERSION 0x00010000
uint64_t data_offset;
uint32_t timestamp;
char creator_tool;
char creator_tool[4];
#define VHD_CREATOR_TOOL_MS_VPC "vpc " /* Virtual PC */
#define VHD_CREATOR_TOOL_MS_VS "vs " /* Virtual Server */
#define VHD_CREATOR_TOOL_FBSD "mkim" /* FreeBSD mkimg */
@ -90,7 +92,8 @@ struct vhd_footer {
uint8_t saved_state;
uint8_t _reserved[427];
};
_Static_assert(sizeof(struct vhd_footer) == 512, "Wrong size for footer");
_Static_assert(sizeof(struct vhd_footer) == VHD_SECTOR_SIZE,
"Wrong size for footer");
struct vhd_dyn_header {
uint64_t cookie;
@ -113,7 +116,8 @@ struct vhd_dyn_header {
} parent_locator[8];
char _reserved2[256];
};
_Static_assert(sizeof(struct vhd_dyn_header) == 1024, "Wrong size for header");
_Static_assert(sizeof(struct vhd_dyn_header) == VHD_SECTOR_SIZE * 2,
"Wrong size for header");
static int
vhd_resize(lba_t imgsz)
@ -124,10 +128,76 @@ vhd_resize(lba_t imgsz)
return (image_set_size(imgsz));
}
static uint32_t
vhd_checksum(void *buf, size_t sz)
{
uint8_t *p = buf;
uint32_t sum;
size_t ofs;
sum = 0;
for (ofs = 0; ofs < sz; ofs++)
sum += p[ofs];
return (~sum);
}
static uint32_t
vhd_timestamp(void)
{
time_t t;
t = time(NULL);
return (t - 0x386d4380);
}
static void
vhd_uuid_enc(void *buf, const uuid_t *uuid)
{
uint8_t *p = buf;
int i;
be32enc(p, uuid->time_low);
be16enc(p + 4, uuid->time_mid);
be16enc(p + 6, uuid->time_hi_and_version);
p[8] = uuid->clock_seq_hi_and_reserved;
p[9] = uuid->clock_seq_low;
for (i = 0; i < _UUID_NODE_LEN; i++)
p[10 + i] = uuid->node[i];
}
static int
vhd_write(int fd)
{
struct vhd_footer footer;
struct vhd_dyn_header header;
uuid_t id;
uint64_t imgsz;
imgsz = image_get_size() * secsz;
memset(&footer, 0, sizeof(footer));
strncpy(footer.cookie, VHD_COOKIE_FREEBSD, sizeof(footer.cookie));
be32enc(&footer.features, VHD_FEATURES_RESERVED);
be32enc(&footer.version, VHD_VERSION);
be32enc(&footer.data_offset, VHD_SECTOR_SIZE);
be32enc(&footer.timestamp, vhd_timestamp());
strncpy(footer.creator_tool, VHD_CREATOR_TOOL_FBSD,
sizeof(footer.creator_tool));
be32enc(&footer.creator_version, VHD_CREATOR_VERS_FBSD);
strncpy(footer.creator_os, VHD_CREATOR_OS_FREEBSD,
sizeof(footer.creator_os));
be64enc(&footer.original_size, imgsz);
be64enc(&footer.current_size, imgsz);
/* XXX Geometry */
be32enc(&footer.disk_type, VHD_DISK_TYPE_DYNAMIC);
uuidgen(&id, 1);
vhd_uuid_enc(&footer.id, &id);
be32enc(&footer.checksum, vhd_checksum(&footer, sizeof(footer)));
if (sparse_write(fd, &footer, VHD_SECTOR_SIZE) < 0)
return (errno);
memset(&header, 0, sizeof(header));
return (image_copyout(fd));
}