Add preliminary QCow2 image support. Supports backing files only with aboslute paths. No compression, encryption, or snapshots.

This commit is contained in:
Michael Greger 2016-02-22 20:57:33 -05:00
parent de057369ce
commit fe0974b9a3
14 changed files with 619 additions and 27 deletions

10
aclocal.m4 vendored
View File

@ -103,10 +103,9 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
@ -573,7 +572,8 @@ to "yes", and re-run configure.
END
AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
fi
fi])
fi
])
dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further

5
configure vendored
View File

@ -2944,8 +2944,8 @@ test "$program_suffix" != NONE &&
ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
if test x"${MISSING+set}" != xset; then
case $am_aux_dir in
@ -3350,6 +3350,7 @@ END
as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
fi
fi
ac_config_headers="$ac_config_headers config.h"

View File

@ -29,6 +29,7 @@ paging.h \
pci_bus.h \
pic.h \
programs.h \
qcow2_disk.h \
render.h \
regs.h \
render.h \

View File

@ -268,6 +268,7 @@ paging.h \
pci_bus.h \
pic.h \
programs.h \
qcow2_disk.h \
render.h \
regs.h \
render.h \

140
include/qcow2_disk.h Normal file
View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2016 Michael Greger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef DOSBOX_QCOW2_DISK_H
#define DOSBOX_QCOW2_DISK_H
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdint.h>
#include "config.h"
#include "bios_disk.h"
class QCow2Image{
public:
static const Bit32u magic = 0x514649FB;
typedef struct QCow2Header {
Bit32u magic;
Bit32u version;
Bit64u backing_file_offset;
Bit32u backing_file_size;
Bit32u cluster_bits;
Bit64u size; /* in bytes */
Bit32u crypt_method;
Bit32u l1_size;
Bit64u l1_table_offset;
Bit64u refcount_table_offset;
Bit32u refcount_table_clusters;
Bit32u nb_snapshots;
Bit64u snapshots_offset;
} QCow2Header;
static QCow2Header read_header(FILE* qcow2File);
QCow2Image(QCow2Header qcow2_header, FILE *qcow2File);
virtual ~QCow2Image();
Bit8u read_sector(Bit32u sectnum, Bit8u* data);
Bit8u write_sector(Bit32u sectnum, Bit8u* data);
private:
static Bit16u host_read16(Bit16u buffer);
static Bit32u host_read32(Bit32u buffer);
static Bit64u host_read64(Bit64u buffer);
static Bit64u mask64(Bit64u bits);
Bit8u pad_file(Bit64u& new_file_length);
Bit8u read_allocated_data(Bit64u file_offset, Bit8u* data, Bit64u data_size);
Bit8u read_cluster(Bit64u data_cluster_number, Bit8u* data);
Bit8u read_l1_table(Bit64u address, Bit64u& l2_table_offset);
Bit8u read_l2_table(Bit64u l2_table_offset, Bit64u address, Bit64u& data_cluster_offset);
Bit8u read_refcount_table(Bit64u data_cluster_offset, Bit64u& refcount_cluster_offset);
Bit8u read_table(Bit64u entry_offset, Bit64u entry_mask, Bit64u& entry_value);
Bit8u read_unallocated_cluster(Bit64u data_cluster_number, Bit8u* data);
Bit8u read_unallocated_sector(Bit32u sectnum, Bit8u* data);
Bit8u update_reference_count(Bit64u cluster_offset, Bit8u* cluster_buffer);
Bit8u write_data(Bit64u file_offset, Bit8u* data, Bit64u data_size);
Bit8u write_l1_table_entry(Bit64u address, Bit64u l2_table_offset);
Bit8u write_l2_table_entry(Bit64u l2_table_offset, Bit64u address, Bit64u data_cluster_offset);
Bit8u write_refcount(Bit64u cluster_offset, Bit64u refcount_cluster_offset, Bit16u refcount);
Bit8u write_refcount_table_entry(Bit64u cluster_offset, Bit64u refcount_cluster_offset);
Bit8u write_table_entry(Bit64u entry_offset, Bit64u entry_value);
FILE* file;
QCow2Header header;
static const Bit64u copy_flag = 0x8000000000000000;
static const Bit64u empty_mask = 0xFFFFFFFFFFFFFFFF;
static const Bit32u sector_size = 512;
static const Bit64u table_entry_mask = 0x00FFFFFFFFFFFFFF;
Bit64u cluster_mask;
Bit64u cluster_size;
Bit64u sectors_per_cluster;
Bit64u disk_sectors_total;
Bit64u l2_mask;
Bit64u l2_bits;
Bit64u l1_bits;
Bit64u refcount_mask;
Bit64u refcount_bits;
QCow2Image* backing_image = NULL;
};
class QCow2Disk : public imageDisk{
public:
QCow2Disk(QCow2Image::QCow2Header qcow2_header, FILE *qcow2File, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk);
virtual ~QCow2Disk();
virtual Bit8u Read_AbsoluteSector(Bit32u sectnum, void* data);
virtual Bit8u Write_AbsoluteSector(Bit32u sectnum, void* data);
private:
QCow2Image qcowImage;
};
#endif

View File

@ -37,7 +37,8 @@
#include "bios.h"
#include "inout.h"
#include "dma.h"
#include "bios_disk.h"
#include "bios_disk.h"
#include "qcow2_disk.h"
#include "setup.h"
#include "control.h"
#include <time.h>
@ -2658,18 +2659,28 @@ public:
return;
}
FILE *newDisk = fopen64(temp_line.c_str(), "rb+");
fseeko64(newDisk,0L, SEEK_END);
/* auto-fill: sector size */
if (sizes[0] == 0) sizes[0] = 512;
Bit64u sectors = (Bit64u)ftello64(newDisk) / (Bit64u)sizes[0];
FILE *newDisk = fopen64(temp_line.c_str(), "rb+");
imagesize = (Bit32u)(sectors / 2); /* orig. code wants it in KBs */
setbuf(newDisk,NULL);
newImage = new imageDisk(newDisk, (Bit8u *)temp_line.c_str(), imagesize, (imagesize > 2880));
QCow2Image::QCow2Header qcow2_header = QCow2Image::read_header(newDisk);
Bit64u sectors;
if (qcow2_header.magic == QCow2Image::magic && (qcow2_header.version == 2 || qcow2_header.version == 3)){
sectors = qcow2_header.size / 512; /* TODO: Currently only supporting 512 byte sectors */
imagesize = (Bit32u)(sectors / 2);
setbuf(newDisk,NULL);
newImage = new QCow2Disk(qcow2_header, newDisk, (Bit8u *)temp_line.c_str(), imagesize, (imagesize > 2880));
}
else{
fseeko64(newDisk,0L, SEEK_END);
sectors = (Bit64u)ftello64(newDisk) / (Bit64u)sizes[0];
imagesize = (Bit32u)(sectors / 2); /* orig. code wants it in KBs */
setbuf(newDisk,NULL);
newImage = new imageDisk(newDisk, (Bit8u *)temp_line.c_str(), imagesize, (imagesize > 2880));
}
newImage->Addref();
/* auto-fill: sector/track count */

View File

@ -28,6 +28,7 @@
#include "cross.h"
#include "bios.h"
#include "bios_disk.h"
#include "qcow2_disk.h"
#define IMGTYPE_FLOPPY 0
#define IMGTYPE_ISO 1
@ -654,11 +655,19 @@ fatDrive::fatDrive(const char *sysFilename, Bit32u bytesector, Bit32u cylsector,
diskfile = fopen64(sysFilename, "rb+");
if(!diskfile) {created_successfully = false;return;}
fseeko64(diskfile, 0L, SEEK_END);
filesize = (Bit32u)(ftello64(diskfile) / 1024L);
QCow2Image::QCow2Header qcow2_header = QCow2Image::read_header(diskfile);
if (qcow2_header.magic == QCow2Image::magic && (qcow2_header.version == 2 || qcow2_header.version == 3)){
filesize = (Bit32u)(qcow2_header.size / 1024L);
loadedDisk = new QCow2Disk(qcow2_header, diskfile, (Bit8u *)sysFilename, filesize, (filesize > 2880));
}
else{
fseeko64(diskfile, 0L, SEEK_END);
filesize = (Bit32u)(ftello64(diskfile) / 1024L);
loadedDisk = new imageDisk(diskfile, (Bit8u *)sysFilename, filesize, (filesize > 2880));
}
/* Load disk image */
loadedDisk = new imageDisk(diskfile, (Bit8u *)sysFilename, filesize, (filesize > 2880));
if(!loadedDisk) {
created_successfully = false;
return;

View File

@ -4,4 +4,4 @@ noinst_LIBRARIES = libints.a
libints_a_SOURCES = mouse.cpp xms.cpp xms.h ems.cpp \
int10.cpp int10.h int10_char.cpp int10_memory.cpp int10_misc.cpp int10_modes.cpp \
int10_vesa.cpp int10_pal.cpp int10_put_pixel.cpp int10_video_state.cpp int10_vptable.cpp \
bios.cpp bios_disk.cpp bios_keyboard.cpp
bios.cpp bios_disk.cpp bios_keyboard.cpp qcow2_disk.cpp

View File

@ -105,7 +105,7 @@ am_libints_a_OBJECTS = mouse.$(OBJEXT) xms.$(OBJEXT) ems.$(OBJEXT) \
int10_vesa.$(OBJEXT) int10_pal.$(OBJEXT) \
int10_put_pixel.$(OBJEXT) int10_video_state.$(OBJEXT) \
int10_vptable.$(OBJEXT) bios.$(OBJEXT) bios_disk.$(OBJEXT) \
bios_keyboard.$(OBJEXT)
bios_keyboard.$(OBJEXT) qcow2_disk.$(OBJEXT)
libints_a_OBJECTS = $(am_libints_a_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@ -287,7 +287,7 @@ noinst_LIBRARIES = libints.a
libints_a_SOURCES = mouse.cpp xms.cpp xms.h ems.cpp \
int10.cpp int10.h int10_char.cpp int10_memory.cpp int10_misc.cpp int10_modes.cpp \
int10_vesa.cpp int10_pal.cpp int10_put_pixel.cpp int10_video_state.cpp int10_vptable.cpp \
bios.cpp bios_disk.cpp bios_keyboard.cpp
bios.cpp bios_disk.cpp bios_keyboard.cpp qcow2_disk.cpp
all: all-am
@ -353,6 +353,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/int10_video_state.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/int10_vptable.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mouse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qcow2_disk.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xms.Po@am__quote@
.cpp.o:

View File

@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "dosbox.h"
#include "callback.h"
#include "bios.h"
@ -65,7 +64,6 @@ Bits swapPosition;
imageDisk *GetINT13FloppyDrive(unsigned char drv) {
if (drv >= 2)
return NULL;
return imageDiskList[drv];
}

422
src/ints/qcow2_disk.cpp Normal file
View File

@ -0,0 +1,422 @@
/*
* Copyright (C) 2016 Michael Greger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "qcow2_disk.h"
using namespace std;
//Public function to read a QCow2 header.
QCow2Image::QCow2Header QCow2Image::read_header(FILE* qcow2File){
QCow2Header header = QCow2Header();
if (1 != fseek(qcow2File, 0, SEEK_SET)){
clearerr(qcow2File);
}
fread(&header, sizeof header, 1, qcow2File);
header.magic = host_read32(header.magic);
header.version = host_read32(header.version);
header.backing_file_offset = host_read64(header.backing_file_offset);
header.backing_file_size = host_read32(header.backing_file_size);
header.cluster_bits = host_read32(header.cluster_bits);
header.size = host_read64(header.size);
header.crypt_method = host_read32(header.crypt_method);
header.l1_size = host_read32(header.l1_size);
header.l1_table_offset = host_read64(header.l1_table_offset);
header.refcount_table_offset = host_read64(header.refcount_table_offset);
header.refcount_table_clusters = host_read32(header.refcount_table_clusters);
header.nb_snapshots = host_read32(header.nb_snapshots);
header.snapshots_offset = host_read64(header.snapshots_offset);
return header;
}
//Public Constructor.
QCow2Image::QCow2Image(QCow2Image::QCow2Header qcow2_header, FILE *qcow2File) : file(qcow2File), header(qcow2_header)
{
cluster_mask = mask64(header.cluster_bits);
cluster_size = cluster_mask + 1;
sectors_per_cluster = cluster_size / sector_size;
disk_sectors_total = header.size/sector_size;
l2_bits = header.cluster_bits - 3;
l2_mask = mask64(l2_bits);
l1_bits = header.cluster_bits + l2_bits;
refcount_bits = header.cluster_bits - 1;
refcount_mask = mask64(refcount_bits);
if (header.backing_file_offset != 0 && header.backing_file_size != 0){
char* backing_file_name = new char[header.backing_file_size];
fseek(file, header.backing_file_offset, SEEK_SET);
fread(backing_file_name, header.backing_file_size, 1, file);
FILE* backing_file = fopen(backing_file_name, "rb");
QCow2Header backing_header = read_header(backing_file);
backing_image = new QCow2Image(backing_header, backing_file);
delete[] backing_file_name;
}
}
//Public Destructor.
QCow2Image::~QCow2Image(){
if (backing_image != NULL){
fclose(backing_image->file);
delete backing_image;
}
}
//Public function to a read a sector.
Bit8u QCow2Image::read_sector(Bit32u sectnum, Bit8u* data){
const Bit64u address = (Bit64u)sectnum * sector_size;
if (address >= header.size){
return 0x05;
}
Bit64u l2_table_offset;
if (0 != read_l1_table(address, l2_table_offset)){
return 0x05;
}
if (0 == l2_table_offset){
return read_unallocated_sector(sectnum, data);
}
Bit64u data_cluster_offset;
if (0 != read_l2_table(l2_table_offset, address, data_cluster_offset)){
return 0x05;
}
if (0 == data_cluster_offset){
return read_unallocated_sector(sectnum, data);
}
return read_allocated_data(data_cluster_offset + (address & cluster_mask), data, sector_size);
}
//Public function to a write a sector.
Bit8u QCow2Image::write_sector(Bit32u sectnum, Bit8u* data){
const Bit64u address = (Bit64u)sectnum * sector_size;
if (address >= header.size){
return 0x05;
}
Bit64u l2_table_offset;
if (0 != read_l1_table(address, l2_table_offset)){
return 0x05;
}
if (0 == l2_table_offset){
if (0 != pad_file(l2_table_offset)){
return 0x05;
}
if (0 != write_l1_table_entry(address, l2_table_offset)){
return 0x05;
}
Bit8u* cluster_buffer = new Bit8u[cluster_size];
std::fill(cluster_buffer, cluster_buffer + cluster_size, 0);
if (0 != write_data(l2_table_offset, cluster_buffer, cluster_size)){
delete[] cluster_buffer;
return 0x05;
}
if (0 != update_reference_count(l2_table_offset, cluster_buffer)){
delete[] cluster_buffer;
return 0x05;
}
delete[] cluster_buffer;
}
Bit64u data_cluster_offset;
if (0 != read_l2_table(l2_table_offset, address, data_cluster_offset)){
return 0x05;
}
if (data_cluster_offset == 0){
if (0 != pad_file(data_cluster_offset)){
return 0x05;
}
if (0 != write_l2_table_entry(l2_table_offset, address, data_cluster_offset)){
return 0x05;
}
Bit8u* cluster_buffer = new Bit8u[cluster_size];
if ( 0 != read_unallocated_cluster(address/cluster_size, cluster_buffer)){
delete[] cluster_buffer;
return 0x05;
}
const Bit64u cluster_buffer_sector_offset = address & cluster_mask;
for (Bit64u i = 0; i < sector_size; i++){
cluster_buffer[cluster_buffer_sector_offset + i] = data[i];
}
if (0 != write_data(data_cluster_offset, cluster_buffer, cluster_size)){
delete[] cluster_buffer;
return 0x05;
}
if (0 != update_reference_count(data_cluster_offset, cluster_buffer)){
delete[] cluster_buffer;
return 0x05;
}
delete[] cluster_buffer;
return 0;
}
return write_data(data_cluster_offset + (address & cluster_mask), data, sector_size);
}
//Helper functions for endianness. QCOW format is big endian so we need different functions than those defined in mem.h.
#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
Bit16u QCow2Image::host_read16(Bit16u buffer) {
return buffer;
}
Bit32u QCow2Image::host_read32(Bit32u buffer) {
return buffer;
}
Bit64u QCow2Image::host_read64(Bit64u buffer) {
return buffer;
}
#else
Bit16u QCow2Image::host_read16(Bit16u buffer) {
Bit8u* b = (Bit8u*)&buffer;
return b[1] | (b[0] << 8);
}
Bit32u QCow2Image::host_read32(Bit32u buffer) {
Bit8u* b = (Bit8u*)&buffer;
return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);
}
Bit64u QCow2Image::host_read64(Bit64u buffer) {
Bit8u* b = (Bit8u*)&buffer;
return b[7] | (b[6] << 8) | (b[5] << 16) | (b[4] << 24) | ((Bit64u)b[3] << 32) | ((Bit64u)b[2] << 40) | ((Bit64u)b[1] << 48) | ((Bit64u)b[0] << 56);
}
#endif
//Generate a mask for a given number of bits.
Bit64u QCow2Image::mask64(Bit64u bits){
return (1 << bits) - 1;
}
//Pad a file with zeros if it doesn't end on a cluster boundary.
Bit8u QCow2Image::pad_file(Bit64u& new_file_length){
if (0 != fseek(file, 0, SEEK_END)){
return 0x05;
}
const Bit64u old_file_length = ftell(file);
const Bit64u padding_size = (cluster_size - (old_file_length % cluster_size)) % cluster_size;
new_file_length = old_file_length + padding_size;
if (0 == padding_size){
return 0;
}
Bit8u* padding = new Bit8u[padding_size];
std::fill(padding, padding + padding_size, 0);
Bit8u result = write_data(old_file_length, padding, padding_size);
delete[] padding;
return result;
}
//Read data of arbitrary length that is present in the image file.
Bit8u QCow2Image::read_allocated_data(Bit64u file_offset, Bit8u* data, Bit64u data_size)
{
if (0 != fseek(file, file_offset, SEEK_SET)){
return 0x05;
}
if (1 != fread(data, data_size, 1, file)){
return 0x05;
}
return 0;
}
//Read an entire cluster that may or may not be allocated in the image file.
inline Bit8u QCow2Image::read_cluster(Bit64u data_cluster_number, Bit8u* data)
{
const Bit64u address = data_cluster_number * cluster_size;
if (address >= header.size){
return 0x05;
}
Bit64u l2_table_offset;
if (0 != read_l1_table(address, l2_table_offset)){
return 0x05;
}
if (0 == l2_table_offset){
return read_unallocated_cluster(data_cluster_number, data);
}
Bit64u data_cluster_offset;
if (0 != read_l2_table(l2_table_offset, address, data_cluster_offset)){
return 0x05;
}
if (0 == data_cluster_offset){
return read_unallocated_cluster(data_cluster_number, data);
}
return read_allocated_data(data_cluster_offset, data, cluster_size);
}
//Read the L1 table to get the offset of the L2 table for a given address.
inline Bit8u QCow2Image::read_l1_table(Bit64u address, Bit64u& l2_table_offset){
const Bit64u l1_entry_offset = header.l1_table_offset + ((address >> l1_bits) << 3);
return read_table(l1_entry_offset, table_entry_mask, l2_table_offset);
}
//Read an L2 table to get the offset of the data cluster for a given address.
inline Bit8u QCow2Image::read_l2_table(Bit64u l2_table_offset, Bit64u address, Bit64u& data_cluster_offset){
const Bit64u l2_entry_offset = l2_table_offset + (((address >> header.cluster_bits) & l2_mask) << 3);
return read_table(l2_entry_offset, table_entry_mask, data_cluster_offset);
}
//Read the refcount table to get the offset of the refcount cluster for a given address.
inline Bit8u QCow2Image::read_refcount_table(Bit64u data_cluster_offset, Bit64u& refcount_cluster_offset){
const Bit64u refcount_entry_offset = header.refcount_table_offset + (((data_cluster_offset/cluster_size) >> refcount_bits) << 3);
return read_table(refcount_entry_offset, empty_mask, refcount_cluster_offset);
}
//Read a table entry at the given offset.
inline Bit8u QCow2Image::read_table(Bit64u entry_offset, Bit64u entry_mask, Bit64u& entry_value){
Bit64u buffer;
if (0 != read_allocated_data(entry_offset, (Bit8u*)&buffer, sizeof buffer)){
return 0x05;
}
entry_value = host_read64(buffer) & table_entry_mask;
return 0;
}
//Read a cluster not currently allocated in the image file.
inline Bit8u QCow2Image::read_unallocated_cluster(Bit64u data_cluster_number, Bit8u* data)
{
if(backing_image == NULL){
std::fill(data, data + cluster_size, 0);
return 0;
}
return backing_image->read_cluster(data_cluster_number, data);
}
//Read a sector not currently allocated in the image file.
inline Bit8u QCow2Image::read_unallocated_sector(Bit32u sectnum, Bit8u* data){
if(backing_image == NULL){
std::fill(data, data+sector_size, 0);
return 0;
}
return backing_image->read_sector(sectnum, data);
}
//Update the reference count for a cluster.
inline Bit8u QCow2Image::update_reference_count(Bit64u cluster_offset, Bit8u* cluster_buffer){
Bit64u refcount_cluster_offset;
if (0 != read_refcount_table(cluster_offset, refcount_cluster_offset)){
return 0x05;
}
if (0 == refcount_cluster_offset){
refcount_cluster_offset = cluster_offset + cluster_size;
std::fill(cluster_buffer, cluster_buffer + cluster_size, 0);
if (0 != write_refcount_table_entry(cluster_offset, refcount_cluster_offset)){
return 0x05;
}
if (0 != write_data(refcount_cluster_offset, cluster_buffer, cluster_size)){
return 0x05;
}
if (0 != write_refcount(refcount_cluster_offset, refcount_cluster_offset, 0x1)){
return 0x05;
}
}
if (0 != write_refcount(cluster_offset, refcount_cluster_offset, 0x1)){
return 0x05;
}
return 0;
}
//Write data of arbitrary length to the image file.
inline Bit8u QCow2Image::write_data(Bit64u file_offset, Bit8u* data, Bit64u data_size){
if (0 != fseek(file, file_offset, SEEK_SET)){
return 0x05;
}
if (1 != fwrite(data, data_size, 1, file)){
return 0x05;
}
return 0;
}
//Write an L2 table offset into the L1 table.
inline Bit8u QCow2Image::write_l1_table_entry(Bit64u address, Bit64u l2_table_offset){
const Bit64u l1_entry_offset = header.l1_table_offset + ((address >> l1_bits) << 3);
return write_table_entry(l1_entry_offset, l2_table_offset | copy_flag);
}
//Write a data cluster offset into an L2 table.
inline Bit8u QCow2Image::write_l2_table_entry(Bit64u l2_table_offset, Bit64u address, Bit64u data_cluster_offset){
const Bit64u l2_entry_offset = l2_table_offset + (((address >> header.cluster_bits) & l2_mask) << 3);
return write_table_entry(l2_entry_offset, data_cluster_offset | copy_flag);
}
//Write a refcount.
inline Bit8u QCow2Image::write_refcount(Bit64u cluster_offset, Bit64u refcount_cluster_offset, Bit16u refcount){
const Bit64u refcount_offset = refcount_cluster_offset + (((cluster_offset/cluster_size) & refcount_mask) << 1);
Bit16u buffer = host_read16(refcount);
return write_data(refcount_offset, (Bit8u*)&buffer, sizeof buffer);
}
//Write a refcount table entry.
inline Bit8u QCow2Image::write_refcount_table_entry(Bit64u cluster_offset, Bit64u refcount_cluster_offset){
const Bit64u refcount_entry_offset = header.refcount_table_offset + (((cluster_offset/cluster_size) >> refcount_bits) << 3);
return write_table_entry(refcount_entry_offset, refcount_cluster_offset);
}
//Write a table entry at the given offset.
inline Bit8u QCow2Image::write_table_entry(Bit64u entry_offset, Bit64u entry_value){
Bit64u buffer = host_read64(entry_value);
return write_data(entry_offset, (Bit8u*)&buffer, sizeof buffer);
}
//Public Constructor.
QCow2Disk::QCow2Disk(QCow2Image::QCow2Header header, FILE *qcow2File, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk) : imageDisk(qcow2File, imgName, imgSizeK, isHardDisk), qcowImage(header, qcow2File){
}
//Public Destructor.
QCow2Disk::~QCow2Disk(){
}
//Public function to a read a sector.
Bit8u QCow2Disk::Read_AbsoluteSector(Bit32u sectnum, void* data){
return qcowImage.read_sector(sectnum, (Bit8u*)data);
}
//Public function to a write a sector.
Bit8u QCow2Disk::Write_AbsoluteSector(Bit32u sectnum, void* data){
return qcowImage.write_sector(sectnum, (Bit8u*)data);
}

View File

@ -850,6 +850,10 @@
RelativePath="..\src\hardware\ps1_sound.cpp"
>
</File>
<File
RelativePath="..\src\ints\qcow2_disk.cpp"
>
</File>
<File
RelativePath="..\src\gui\render.cpp"
>

View File

@ -393,6 +393,7 @@
<ClCompile Include="..\src\misc\cross.cpp" />
<ClCompile Include="..\src\misc\messages.cpp" />
<ClCompile Include="..\src\misc\programs.cpp" />
<ClCompile Include="..\src\ints\qcow2_disk.cpp" />
<ClCompile Include="..\src\misc\regionalloctracking.cpp" />
<ClCompile Include="..\src\misc\setup.cpp" />
<ClCompile Include="..\src\misc\support.cpp" />
@ -429,4 +430,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -387,6 +387,9 @@
<ClCompile Include="..\src\hardware\ps1_sound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\ints\qcow2_disk.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\gui\render.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -642,4 +645,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
</Project>