DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/ints/qcow2_disk.cpp
00001 /*
00002  *  Copyright (C) 2016  Michael Greger
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include "qcow2_disk.h"
00021 
00022 #if defined(_MSC_VER)
00023 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00024 #endif
00025 
00026 using namespace std;
00027 
00028 
00029 //Public constant.
00030         const Bit32u QCow2Image::magic = 0x514649FB;
00031 
00032 
00033 //Public function to read a QCow2 header.
00034         QCow2Image::QCow2Header QCow2Image::read_header(FILE* qcow2File){
00035                 QCow2Header header;
00036                 fseeko64(qcow2File, 0, SEEK_SET);
00037                 if (1 != fread(&header, sizeof header, 1, qcow2File)){
00038                         clearerr(qcow2File);  /*If we fail, reset the file stream's status*/
00039                         return QCow2Header(); /*Return an empty header*/
00040                 }
00041                 header.magic = host_read32(header.magic);
00042                 header.version = host_read32(header.version);
00043                 header.backing_file_offset = host_read64(header.backing_file_offset);
00044                 header.backing_file_size = host_read32(header.backing_file_size);
00045                 header.cluster_bits = host_read32(header.cluster_bits);
00046                 header.size = host_read64(header.size);
00047                 header.crypt_method = host_read32(header.crypt_method);
00048                 header.l1_size = host_read32(header.l1_size);
00049                 header.l1_table_offset = host_read64(header.l1_table_offset);
00050                 header.refcount_table_offset = host_read64(header.refcount_table_offset);
00051                 header.refcount_table_clusters = host_read32(header.refcount_table_clusters);
00052                 header.nb_snapshots = host_read32(header.nb_snapshots);
00053                 header.snapshots_offset = host_read64(header.snapshots_offset);
00054                 return header;
00055         }
00056 
00057 
00058 //Public Constructor.
00059         QCow2Image::QCow2Image(QCow2Image::QCow2Header qcow2Header, FILE *qcow2File, const char* imageName, Bit32u sectorSizeBytes) : file(qcow2File), header(qcow2Header), sector_size(sectorSizeBytes), backing_image(NULL)
00060         {
00061                 cluster_mask = mask64(header.cluster_bits);
00062                 cluster_size = cluster_mask + 1;
00063                 sectors_per_cluster = cluster_size / sector_size;
00064                 l2_bits = header.cluster_bits - 3;
00065                 l2_mask = mask64(l2_bits);
00066                 l1_bits = header.cluster_bits + l2_bits;
00067                 refcount_bits = header.cluster_bits - 1;
00068                 refcount_mask = mask64(refcount_bits);
00069                 if (header.backing_file_offset != 0 && header.backing_file_size != 0){
00070                         char* backing_file_name = new char[header.backing_file_size + 1];
00071                         backing_file_name[header.backing_file_size] = 0;
00072                         fseeko64(file, (off_t)header.backing_file_offset, SEEK_SET);
00073                         fread(backing_file_name, header.backing_file_size, 1, file);
00074                         if (backing_file_name[0] != 0x2F){
00075                                 for (int image_name_index = (int)strlen(imageName); image_name_index > -1; image_name_index--){
00076                                         if (imageName[image_name_index] == 0x2F){
00077                                                 int full_name_length = (int)((unsigned int)header.backing_file_size + (unsigned int)image_name_index + 2u);
00078                                                 char* full_name = new char[full_name_length];
00079                                                 for(int full_name_index = 0; full_name_index < full_name_length; full_name_index++){
00080                                                         if (full_name_index <= image_name_index){
00081                                                                 full_name[full_name_index] = imageName[full_name_index];
00082                                                         } else {
00083                                                                 full_name[full_name_index] = backing_file_name[full_name_index - (image_name_index + 1)];
00084                                                         }
00085                                                 }
00086                                                 delete[] backing_file_name;
00087                                                 backing_file_name = full_name;
00088                                                 break;
00089                                         }
00090                                 }
00091                         }
00092                         FILE* backing_file = fopen(backing_file_name, "rb");
00093                         if (backing_file != NULL){
00094                                 QCow2Header backing_header = read_header(backing_file);
00095                                 backing_image = new QCow2Image(backing_header, backing_file, backing_file_name, sectorSizeBytes);
00096                         } else {
00097                                 LOG_MSG("Failed to load QCow2 backing image: %s", backing_file_name);
00098                         }
00099                         delete[] backing_file_name;
00100                 }
00101         }
00102 
00103 
00104 //Public Destructor.
00105         QCow2Image::~QCow2Image(){
00106                 if (backing_image != NULL){
00107                         fclose(backing_image->file);
00108                         delete backing_image;
00109                 }
00110         }
00111 
00112 
00113 //Public function to a read a sector.
00114         Bit8u QCow2Image::read_sector(Bit32u sectnum, Bit8u* data){
00115                 const Bit64u address = (Bit64u)sectnum * sector_size;
00116                 if (address >= header.size){
00117                         return 0x05;
00118                 }
00119                 Bit64u l2_table_offset;
00120                 if (0 != read_l1_table(address, l2_table_offset)){
00121                         return 0x05;
00122                 }
00123                 if (0 == l2_table_offset){
00124                         return read_unallocated_sector(sectnum, data);
00125                 }
00126                 Bit64u data_cluster_offset;
00127                 if (0 != read_l2_table(l2_table_offset, address, data_cluster_offset)){
00128                         return 0x05;
00129                 }
00130                 if (0 == data_cluster_offset){
00131                         return read_unallocated_sector(sectnum, data);
00132                 }
00133                 return read_allocated_data(data_cluster_offset + (address & cluster_mask), data, sector_size);
00134         }
00135 
00136 
00137 //Public function to a write a sector.
00138         Bit8u QCow2Image::write_sector(Bit32u sectnum, Bit8u* data){
00139                 const Bit64u address = (Bit64u)sectnum * sector_size;
00140                 if (address >= header.size){
00141                         return 0x05;
00142                 }
00143                 Bit64u l2_table_offset;
00144                 if (0 != read_l1_table(address, l2_table_offset)){
00145                         return 0x05;
00146                 }
00147                 if (0 == l2_table_offset){
00148                         if (0 != pad_file(l2_table_offset)){
00149                                 return 0x05;
00150                         }
00151                         if (0 != write_l1_table_entry(address, l2_table_offset)){
00152                                 return 0x05;
00153                         }
00154                         Bit8u* cluster_buffer = new Bit8u[cluster_size];
00155                         std::fill(cluster_buffer, cluster_buffer + cluster_size, 0);
00156                         if (0 != write_data(l2_table_offset, cluster_buffer, cluster_size)){
00157                                 delete[] cluster_buffer;
00158                                 return 0x05;
00159                         }
00160                         if (0 != update_reference_count(l2_table_offset, cluster_buffer)){
00161                                 delete[] cluster_buffer;
00162                                 return 0x05;
00163                         }
00164                         delete[] cluster_buffer;
00165                 }
00166                 Bit64u data_cluster_offset;
00167                 if (0 != read_l2_table(l2_table_offset, address, data_cluster_offset)){
00168                         return 0x05;
00169                 }
00170                 if (data_cluster_offset == 0){
00171                         if (0 != pad_file(data_cluster_offset)){
00172                                 return 0x05;
00173                         }
00174                         if (0 != write_l2_table_entry(l2_table_offset, address, data_cluster_offset)){
00175                                 return 0x05;
00176                         }
00177                         Bit8u* cluster_buffer = new Bit8u[cluster_size];
00178                         if ( 0 != read_unallocated_cluster(address/cluster_size, cluster_buffer)){
00179                                 delete[] cluster_buffer;
00180                                 return 0x05;
00181                         }
00182                         const Bit64u cluster_buffer_sector_offset = address & cluster_mask;
00183                         for (Bit64u i = 0; i < sector_size; i++){
00184                                 cluster_buffer[cluster_buffer_sector_offset + i] = data[i];
00185                         }
00186                         if (0 != write_data(data_cluster_offset, cluster_buffer, cluster_size)){
00187                                 delete[] cluster_buffer;
00188                                 return 0x05;
00189                         }
00190                         if (0 != update_reference_count(data_cluster_offset, cluster_buffer)){
00191                                 delete[] cluster_buffer;
00192                                 return 0x05;
00193                         }
00194                         delete[] cluster_buffer;
00195                         return 0;
00196                 }
00197                 return write_data(data_cluster_offset + (address & cluster_mask), data, sector_size);
00198         }
00199 
00200 
00201 //Private constants.
00202         const Bit64u QCow2Image::copy_flag = 0x8000000000000000;
00203         const Bit64u QCow2Image::empty_mask = 0xFFFFFFFFFFFFFFFF;
00204         const Bit64u QCow2Image::table_entry_mask = 0x00FFFFFFFFFFFFFF;
00205 
00206 
00207 //Helper functions for endianness. QCOW format is big endian so we need different functions than those defined in mem.h.
00208 #if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
00209 
00210 
00211         inline Bit16u QCow2Image::host_read16(Bit16u buffer) {
00212                 return buffer;
00213         }
00214 
00215 
00216         inline Bit32u QCow2Image::host_read32(Bit32u buffer) {
00217                 return buffer;
00218         }
00219 
00220 
00221         inline Bit64u QCow2Image::host_read64(Bit64u buffer) {
00222                 return buffer;
00223         }
00224 
00225 
00226 #else
00227 
00228 
00229         inline Bit16u QCow2Image::host_read16(Bit16u buffer) {
00230                 Bit8u* b = (Bit8u*)&buffer;
00231                 return (unsigned int)b[1] | ((unsigned int)b[0] << 8u);
00232         }
00233 
00234 
00235         inline Bit32u QCow2Image::host_read32(Bit32u buffer) {
00236                 Bit8u* b = (Bit8u*)&buffer;
00237                 return (Bit32u)b[3] | ((Bit32u)b[2] << 8u) | ((Bit32u)b[1] << 16u) | ((Bit32u)b[0] << 24u);
00238         }
00239 
00240 
00241         inline Bit64u QCow2Image::host_read64(Bit64u buffer) {
00242                 Bit8u* b = (Bit8u*)&buffer;
00243                 return
00244             (unsigned int)b[7] | ((unsigned int)b[6] << 8u) |
00245             ((unsigned int)b[5] << 16u) | ((unsigned int)b[4] << 24u) |
00246             ((Bit64u)b[3] << 32u) | ((Bit64u)b[2] << 40u) | ((Bit64u)b[1] << 48u) | ((Bit64u)b[0] << 56u);
00247         }
00248 
00249 
00250 #endif
00251 
00252 
00253 //Generate a mask for a given number of bits.
00254         inline Bit64u QCow2Image::mask64(Bit64u bits){
00255                 return (1ull << bits) - 1ull;
00256         }
00257 
00258 
00259 //Pad a file with zeros if it doesn't end on a cluster boundary.
00260         Bit8u QCow2Image::pad_file(Bit64u& new_file_length){
00261                 if (0 != fseeko64(file, 0, SEEK_END)){
00262                         return 0x05;
00263                 }
00264                 const Bit64u old_file_length = (Bit64u)ftello64(file);
00265                 const Bit64u padding_size = (cluster_size - (old_file_length % cluster_size)) % cluster_size;
00266                 new_file_length = old_file_length + padding_size;
00267                 if (0 == padding_size){
00268                         return 0;
00269                 }
00270                 Bit8u* padding = new Bit8u[padding_size];
00271                 std::fill(padding, padding + padding_size, 0);
00272                 Bit8u result = write_data(old_file_length, padding, padding_size);
00273                 delete[] padding;
00274                 return result;
00275         }
00276 
00277 
00278 //Read data of arbitrary length that is present in the image file.
00279         Bit8u QCow2Image::read_allocated_data(Bit64u file_offset, Bit8u* data, Bit64u data_size)
00280         {
00281                 if (0 != fseeko64(file, (off_t)file_offset, SEEK_SET)){
00282                         return 0x05;
00283                 }
00284                 if (1 != fread(data, data_size, 1, file)){
00285                         return 0x05;
00286                 }
00287                 return 0;
00288         }
00289 
00290 
00291 //Read an entire cluster that may or may not be allocated in the image file.
00292         Bit8u QCow2Image::read_cluster(Bit64u data_cluster_number, Bit8u* data)
00293         {
00294                 const Bit64u address = data_cluster_number * cluster_size;
00295                 if (address >= header.size){
00296                         return 0x05;
00297                 }
00298                 Bit64u l2_table_offset;
00299                 if (0 != read_l1_table(address, l2_table_offset)){
00300                         return 0x05;
00301                 }
00302                 if (0 == l2_table_offset){
00303                         return read_unallocated_cluster(data_cluster_number, data);
00304                 }
00305                 Bit64u data_cluster_offset;
00306                 if (0 != read_l2_table(l2_table_offset, address, data_cluster_offset)){
00307                         return 0x05;
00308                 }
00309                 if (0 == data_cluster_offset){
00310                         return read_unallocated_cluster(data_cluster_number, data);
00311                 }
00312                 return read_allocated_data(data_cluster_offset, data, cluster_size);
00313         }
00314 
00315 
00316 //Read the L1 table to get the offset of the L2 table for a given address.
00317         inline Bit8u QCow2Image::read_l1_table(Bit64u address, Bit64u& l2_table_offset){
00318                 const Bit64u l1_entry_offset = header.l1_table_offset + ((address >> l1_bits) << 3);
00319                 return read_table(l1_entry_offset, table_entry_mask, l2_table_offset);
00320         }
00321 
00322 
00323 //Read an L2 table to get the offset of the data cluster for a given address.
00324         inline Bit8u QCow2Image::read_l2_table(Bit64u l2_table_offset, Bit64u address, Bit64u& data_cluster_offset){
00325                 const Bit64u l2_entry_offset = l2_table_offset + (((address >> header.cluster_bits) & l2_mask) << 3);
00326                 return read_table(l2_entry_offset, table_entry_mask, data_cluster_offset);
00327         }
00328 
00329 
00330 //Read the refcount table to get the offset of the refcount cluster for a given address.
00331         inline Bit8u QCow2Image::read_refcount_table(Bit64u data_cluster_offset, Bit64u& refcount_cluster_offset){
00332                 const Bit64u refcount_entry_offset = header.refcount_table_offset + (((data_cluster_offset/cluster_size) >> refcount_bits) << 3);
00333                 return read_table(refcount_entry_offset, empty_mask, refcount_cluster_offset);
00334         }
00335 
00336 
00337 //Read a table entry at the given offset.
00338         inline Bit8u QCow2Image::read_table(Bit64u entry_offset, Bit64u entry_mask, Bit64u& entry_value){
00339         (void)entry_mask;//UNUSED
00340                 Bit64u buffer;
00341                 if (0 != read_allocated_data(entry_offset, (Bit8u*)&buffer, sizeof buffer)){
00342                         return 0x05;
00343                 }
00344                 entry_value = host_read64(buffer) & table_entry_mask;
00345                 return 0;
00346         }
00347 
00348 
00349 //Read a cluster not currently allocated in the image file.
00350         inline Bit8u QCow2Image::read_unallocated_cluster(Bit64u data_cluster_number, Bit8u* data)
00351         {
00352                 if(backing_image == NULL){
00353                         std::fill(data, data + cluster_size, 0);
00354                         return 0;
00355                 }
00356                 return backing_image->read_cluster(data_cluster_number, data);
00357         }
00358 
00359 
00360 //Read a sector not currently allocated in the image file.
00361         inline Bit8u QCow2Image::read_unallocated_sector(Bit32u sectnum, Bit8u* data){
00362                 if(backing_image == NULL){
00363                         std::fill(data, data+sector_size, 0);
00364                         return 0;
00365                 }
00366                 return backing_image->read_sector(sectnum, data);
00367         }
00368 
00369 //Update the reference count for a cluster.
00370         Bit8u QCow2Image::update_reference_count(Bit64u cluster_offset, Bit8u* cluster_buffer){
00371                 Bit64u refcount_cluster_offset;
00372                 if (0 != read_refcount_table(cluster_offset, refcount_cluster_offset)){
00373                         return 0x05;
00374                 }
00375                 if (0 == refcount_cluster_offset){
00376                         refcount_cluster_offset = cluster_offset + cluster_size;
00377                         std::fill(cluster_buffer, cluster_buffer + cluster_size, 0);
00378                         if (0 != write_refcount_table_entry(cluster_offset, refcount_cluster_offset)){
00379                                 return 0x05;
00380                         }
00381                         if (0 != write_data(refcount_cluster_offset, cluster_buffer, cluster_size)){
00382                         return 0x05;
00383                         }
00384                         if (0 != write_refcount(refcount_cluster_offset, refcount_cluster_offset, 0x1)){
00385                                 return 0x05;
00386                         }
00387                 }
00388                 if (0 != write_refcount(cluster_offset, refcount_cluster_offset, 0x1)){
00389                         return 0x05;
00390                 }
00391                 return 0;
00392         }
00393 
00394 
00395 //Write data of arbitrary length to the image file.
00396         Bit8u QCow2Image::write_data(Bit64u file_offset, Bit8u* data, Bit64u data_size){
00397                 if (0 != fseeko64(file, (off_t)file_offset, SEEK_SET)){
00398                         return 0x05;
00399                 }
00400                 if (1 != fwrite(data, data_size, 1, file)){
00401                         return 0x05;
00402                 }
00403                 return 0;
00404         }
00405 
00406 
00407 //Write an L2 table offset into the L1 table.
00408         inline Bit8u QCow2Image::write_l1_table_entry(Bit64u address, Bit64u l2_table_offset){
00409                 const Bit64u l1_entry_offset = header.l1_table_offset + ((address >> l1_bits) << 3);
00410                 return write_table_entry(l1_entry_offset, l2_table_offset | copy_flag);
00411         }
00412 
00413 
00414 //Write a data cluster offset into an L2 table.
00415         inline Bit8u QCow2Image::write_l2_table_entry(Bit64u l2_table_offset, Bit64u address, Bit64u data_cluster_offset){
00416                 const Bit64u l2_entry_offset = l2_table_offset + (((address >> header.cluster_bits) & l2_mask) << 3);
00417                 return write_table_entry(l2_entry_offset, data_cluster_offset | copy_flag);
00418         }
00419 
00420 
00421 //Write a refcount.
00422         inline Bit8u QCow2Image::write_refcount(Bit64u cluster_offset, Bit64u refcount_cluster_offset, Bit16u refcount){
00423                 const Bit64u refcount_offset = refcount_cluster_offset + (((cluster_offset/cluster_size) & refcount_mask) << 1);
00424                 Bit16u buffer = host_read16(refcount);
00425                 return write_data(refcount_offset, (Bit8u*)&buffer, sizeof buffer);
00426         }
00427 
00428 
00429 //Write a refcount table entry.
00430         inline Bit8u QCow2Image::write_refcount_table_entry(Bit64u cluster_offset, Bit64u refcount_cluster_offset){
00431                 const Bit64u refcount_entry_offset = header.refcount_table_offset + (((cluster_offset/cluster_size) >> refcount_bits) << 3);
00432                 return write_table_entry(refcount_entry_offset, refcount_cluster_offset);
00433         }
00434 
00435 
00436 //Write a table entry at the given offset.
00437         inline Bit8u QCow2Image::write_table_entry(Bit64u entry_offset, Bit64u entry_value){
00438                 Bit64u buffer = host_read64(entry_value);
00439                 return write_data(entry_offset, (Bit8u*)&buffer, sizeof buffer);
00440         }
00441 
00442 
00443 //Public Constructor.
00444         QCow2Disk::QCow2Disk(QCow2Image::QCow2Header qcow2Header, FILE *qcow2File, Bit8u *imgName, Bit32u imgSizeK, Bit32u sectorSizeBytes, bool isHardDisk) : imageDisk(qcow2File, imgName, imgSizeK, isHardDisk), qcowImage(qcow2Header, qcow2File, (const char*) imgName, sectorSizeBytes){
00445         }
00446 
00447 
00448 //Public Destructor.
00449         QCow2Disk::~QCow2Disk(){
00450         }
00451 
00452 
00453 //Public function to a read a sector.
00454         Bit8u QCow2Disk::Read_AbsoluteSector(Bit32u sectnum, void* data){
00455                 return qcowImage.read_sector(sectnum, (Bit8u*)data);
00456         }
00457 
00458 
00459 //Public function to a write a sector.
00460         Bit8u QCow2Disk::Write_AbsoluteSector(Bit32u sectnum,const void* data){
00461                 return qcowImage.write_sector(sectnum, (Bit8u*)data);
00462         }