};
typedef struct BDRVVPCState {
- BlockDriverState *hd;
-
uint8_t footer_buf[HEADER_SIZE];
uint64_t free_data_block_offset;
int max_table_entries;
s->last_bitmap_offset = bitmap_offset;
memset(bitmap, 0xff, s->bitmap_size);
- bdrv_pwrite(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+ bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
}
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
BDRVVPCState *s = bs->opaque;
int64_t offset = s->free_data_block_offset;
- ret = bdrv_pwrite(bs->file, offset, s->footer_buf, HEADER_SIZE);
+ ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
if (ret < 0)
return ret;
// Initialize the block's bitmap
memset(bitmap, 0xff, s->bitmap_size);
- bdrv_pwrite(bs->file, s->free_data_block_offset, bitmap, s->bitmap_size);
+ bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
+ s->bitmap_size);
// Write new footer (the old one will be overwritten)
s->free_data_block_offset += s->block_size + s->bitmap_size;
// Write BAT entry to disk
bat_offset = s->bat_offset + (4 * index);
bat_value = be32_to_cpu(s->pagetable[index]);
- ret = bdrv_pwrite(bs->file, bat_offset, &bat_value, 4);
+ ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
if (ret < 0)
goto fail;
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
+ BDRVVPCState *s = bs->opaque;
int ret;
int64_t offset;
+ int64_t sectors, sectors_per_block;
while (nb_sectors > 0) {
offset = get_sector_offset(bs, sector_num, 0);
+ sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
+ sectors = sectors_per_block - (sector_num % sectors_per_block);
+ if (sectors > nb_sectors) {
+ sectors = nb_sectors;
+ }
+
if (offset == -1) {
- memset(buf, 0, 512);
+ memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
} else {
- ret = bdrv_pread(bs->file, offset, buf, 512);
- if (ret != 512)
+ ret = bdrv_pread(bs->file, offset, buf,
+ sectors * BDRV_SECTOR_SIZE);
+ if (ret != sectors * BDRV_SECTOR_SIZE) {
return -1;
+ }
}
- nb_sectors--;
- sector_num++;
- buf += 512;
+ nb_sectors -= sectors;
+ sector_num += sectors;
+ buf += sectors * BDRV_SECTOR_SIZE;
}
return 0;
}
static int vpc_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
+ BDRVVPCState *s = bs->opaque;
int64_t offset;
+ int64_t sectors, sectors_per_block;
int ret;
while (nb_sectors > 0) {
offset = get_sector_offset(bs, sector_num, 1);
+ sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
+ sectors = sectors_per_block - (sector_num % sectors_per_block);
+ if (sectors > nb_sectors) {
+ sectors = nb_sectors;
+ }
+
if (offset == -1) {
offset = alloc_block(bs, sector_num);
if (offset < 0)
return -1;
}
- ret = bdrv_pwrite(bs->file, offset, buf, 512);
- if (ret != 512)
+ ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE);
+ if (ret != sectors * BDRV_SECTOR_SIZE) {
return -1;
+ }
- nb_sectors--;
- sector_num++;
- buf += 512;
+ nb_sectors -= sectors;
+ sector_num += sectors;
+ buf += sectors * BDRV_SECTOR_SIZE;
}
return 0;
}
+static int vpc_flush(BlockDriverState *bs)
+{
+ return bdrv_flush(bs->file);
+}
/*
* Calculates the number of cylinders, heads and sectors per cylinder
}
}
- // Note: Rounding up deviates from the Virtual PC behaviour
- // However, we need this to avoid truncating images in qemu-img convert
- *cyls = (cyls_times_heads + *heads - 1) / *heads;
+ *cyls = cyls_times_heads / *heads;
return 0;
}
struct vhd_dyndisk_header* dyndisk_header =
(struct vhd_dyndisk_header*) buf;
int fd, i;
- uint16_t cyls;
- uint8_t heads;
- uint8_t secs_per_cyl;
+ uint16_t cyls = 0;
+ uint8_t heads = 0;
+ uint8_t secs_per_cyl = 0;
size_t block_size, num_bat_entries;
int64_t total_sectors = 0;
+ int ret = -EIO;
// Read out options
while (options && options->name) {
if (fd < 0)
return -EIO;
- // Calculate matching total_size and geometry
- if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
- return -EFBIG;
+ /* Calculate matching total_size and geometry. Increase the number of
+ sectors requested until we get enough (or fail). */
+ for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
+ if (calculate_geometry(total_sectors + i,
+ &cyls, &heads, &secs_per_cyl)) {
+ ret = -EFBIG;
+ goto fail;
+ }
+ }
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
// Prepare the Hard Disk Footer
block_size = 0x200000;
num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
- if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
- return -EIO;
+ if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+ goto fail;
+ }
- if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0)
- return -EIO;
- if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
- return -EIO;
+ if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0) {
+ goto fail;
+ }
+ if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+ goto fail;
+ }
// Write the initial BAT
- if (lseek(fd, 3 * 512, SEEK_SET) < 0)
- return -EIO;
+ if (lseek(fd, 3 * 512, SEEK_SET) < 0) {
+ goto fail;
+ }
memset(buf, 0xFF, 512);
- for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++)
- if (write(fd, buf, 512) != 512)
- return -EIO;
+ for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++) {
+ if (write(fd, buf, 512) != 512) {
+ goto fail;
+ }
+ }
// Prepare the Dynamic Disk Header
dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
// Write the header
- if (lseek(fd, 512, SEEK_SET) < 0)
- return -EIO;
- if (write(fd, buf, 1024) != 1024)
- return -EIO;
+ if (lseek(fd, 512, SEEK_SET) < 0) {
+ goto fail;
+ }
+ if (write(fd, buf, 1024) != 1024) {
+ goto fail;
+ }
+ ret = 0;
+
+ fail:
close(fd);
- return 0;
+ return ret;
}
static void vpc_close(BlockDriverState *bs)
};
static BlockDriver bdrv_vpc = {
- .format_name = "vpc",
- .instance_size = sizeof(BDRVVPCState),
- .bdrv_probe = vpc_probe,
- .bdrv_open = vpc_open,
- .bdrv_read = vpc_read,
- .bdrv_write = vpc_write,
- .bdrv_close = vpc_close,
- .bdrv_create = vpc_create,
+ .format_name = "vpc",
+ .instance_size = sizeof(BDRVVPCState),
+ .bdrv_probe = vpc_probe,
+ .bdrv_open = vpc_open,
+ .bdrv_read = vpc_read,
+ .bdrv_write = vpc_write,
+ .bdrv_flush = vpc_flush,
+ .bdrv_close = vpc_close,
+ .bdrv_create = vpc_create,
.create_options = vpc_create_options,
};