/*
* Block driver for the COW format
- *
+ *
* Copyright (c) 2004 Fabrice Bellard
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* THE SOFTWARE.
*/
#ifndef _WIN32
-#include "vl.h"
+#include "qemu-common.h"
#include "block_int.h"
#include <sys/mman.h>
{
const struct cow_header_v2 *cow_header = (const void *)buf;
- if (be32_to_cpu(cow_header->magic) == COW_MAGIC &&
- be32_to_cpu(cow_header->version) == COW_VERSION)
+ if (buf_size >= sizeof(struct cow_header_v2) &&
+ be32_to_cpu(cow_header->magic) == COW_MAGIC &&
+ be32_to_cpu(cow_header->version) == COW_VERSION)
return 100;
else
return 0;
}
-static int cow_open(BlockDriverState *bs, const char *filename)
+static int cow_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVCowState *s = bs->opaque;
int fd;
be32_to_cpu(cow_header.version) != COW_VERSION) {
goto fail;
}
-
+
/* cow image found */
size = be64_to_cpu(cow_header.size);
bs->total_sectors = size / 512;
- pstrcpy(bs->backing_file, sizeof(bs->backing_file),
+ pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
-
-#if 0
- if (cow_header.backing_file[0] != '\0') {
- if (stat(cow_header.backing_file, &st) != 0) {
- fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
- goto fail;
- }
- if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
- fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
- goto fail;
- }
- fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
- if (fd < 0)
- goto fail;
- bs->fd = fd;
- }
-#endif
+
/* mmap the bitmap */
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
- s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
- s->cow_bitmap_size,
+ s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
+ s->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, s->fd, 0);
if (s->cow_bitmap_addr == MAP_FAILED)
return changed;
}
-static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
+static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
BDRVCowState *s = bs->opaque;
return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
}
-static int cow_read(BlockDriverState *bs, int64_t sector_num,
+static int cow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, n;
-
+
while (nb_sectors > 0) {
if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
- if (ret != n * 512)
+ if (ret != n * 512)
return -1;
} else {
+ if (bs->backing_hd) {
+ /* read from the base image */
+ ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+ if (ret < 0)
+ return -1;
+ } else {
memset(buf, 0, n * 512);
}
+ }
nb_sectors -= n;
sector_num += n;
buf += n * 512;
return 0;
}
-static int cow_write(BlockDriverState *bs, int64_t sector_num,
+static int cow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVCowState *s = bs->opaque;
int ret, i;
-
+
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
- if (ret != nb_sectors * 512)
+ if (ret != nb_sectors * 512)
return -1;
for (i = 0; i < nb_sectors; i++)
cow_set_bit(s->cow_bitmap, sector_num + i);
if (flags)
return -ENOTSUP;
- cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+ cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
if (cow_fd < 0)
return -1;
cow_header.magic = cpu_to_be32(COW_MAGIC);
cow_header.version = cpu_to_be32(COW_VERSION);
if (image_filename) {
+ /* Note: if no file, we put a dummy mtime */
+ cow_header.mtime = cpu_to_be32(0);
+
fd = open(image_filename, O_RDONLY | O_BINARY);
if (fd < 0) {
close(cow_fd);
- return -1;
+ goto mtime_fail;
}
if (fstat(fd, &st) != 0) {
close(fd);
- return -1;
+ goto mtime_fail;
}
close(fd);
cow_header.mtime = cpu_to_be32(st.st_mtime);
- realpath(image_filename, cow_header.backing_file);
+ mtime_fail:
+ pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
+ image_filename);
}
cow_header.sectorsize = cpu_to_be32(512);
cow_header.size = cpu_to_be64(image_sectors * 512);
return 0;
}
+static void cow_flush(BlockDriverState *bs)
+{
+ BDRVCowState *s = bs->opaque;
+ fsync(s->fd);
+}
+
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
cow_write,
cow_close,
cow_create,
+ cow_flush,
cow_is_allocated,
};
#endif