VirtualBox

source: vbox/trunk/src/VBox/Storage/QCOW.cpp

Last change on this file was 106061, checked in by vboxsync, 3 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 99.9 KB
RevLine 
[38563]1/* $Id: QCOW.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * QCOW - QCOW Disk image.
4 */
5
6/*
[106061]7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
[38563]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[38563]26 */
27
[57358]28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[38623]32#define LOG_GROUP LOG_GROUP_VD_QCOW
[38563]33#include <VBox/vd-plugin.h>
34#include <VBox/err.h>
35
36#include <VBox/log.h>
37#include <iprt/asm.h>
38#include <iprt/assert.h>
39#include <iprt/string.h>
40#include <iprt/alloc.h>
41#include <iprt/path.h>
42#include <iprt/list.h>
[82595]43#include <iprt/zip.h>
[38563]44
[50988]45#include "VDBackends.h"
[66494]46#include "VDBackendsInline.h"
[50988]47
[62745]48/** @page pg_storage_qcow QCOW Storage Backend
49 * The QCOW backend implements support for the qemu copy on write format (short QCOW).
[38563]50 *
[77924]51 * The official specification for qcow is available at
52 * https://github.com/qemu/qemu/blob/master/docs/interop/qcow2.txt version 2 and 3.
53 * For version 1 there is no official specification available but the format is described
54 * at http://people.gnome.org/~markmc/qcow-image-format-version-1.html.
55 *
[38563]56 * Missing things to implement:
57 * - v2 image creation and handling of the reference count table. (Blocker to enable support for V2 images)
58 * - cluster encryption
59 * - cluster compression
60 * - compaction
61 * - resizing
62 */
63
64
[57358]65/*********************************************************************************************************************************
66* Structures in a QCOW image, big endian *
67*********************************************************************************************************************************/
68
[62745]69#pragma pack(1) /* Completely unnecessary. */
[38563]70typedef struct QCowHeader
71{
72 /** Magic value. */
73 uint32_t u32Magic;
74 /** Version of the image. */
75 uint32_t u32Version;
76 /** Version dependent data. */
77 union
78 {
79 /** Version 1. */
80 struct
81 {
82 /** Backing file offset. */
83 uint64_t u64BackingFileOffset;
84 /** Size of the backing file. */
85 uint32_t u32BackingFileSize;
86 /** mtime (Modification time?) - can be ignored. */
87 uint32_t u32MTime;
88 /** Logical size of the image in bytes. */
89 uint64_t u64Size;
90 /** Number of bits in the virtual offset used as a cluster offset. */
91 uint8_t u8ClusterBits;
92 /** Number of bits in the virtual offset used for the L2 index. */
93 uint8_t u8L2Bits;
94 /** Padding because the header is not packed in the original source. */
95 uint16_t u16Padding;
96 /** Used cryptographic method. */
97 uint32_t u32CryptMethod;
98 /** Offset of the L1 table in the image in bytes. */
99 uint64_t u64L1TableOffset;
100 } v1;
[77924]101 /** Version 2 (and also containing extensions for version 3). */
[38563]102 struct
103 {
104 /** Backing file offset. */
105 uint64_t u64BackingFileOffset;
106 /** Size of the backing file. */
107 uint32_t u32BackingFileSize;
108 /** Number of bits in the virtual offset used as a cluster offset. */
109 uint32_t u32ClusterBits;
110 /** Logical size of the image. */
111 uint64_t u64Size;
112 /** Used cryptographic method. */
113 uint32_t u32CryptMethod;
114 /** Size of the L1 table in entries (each 8bytes big). */
115 uint32_t u32L1Size;
116 /** Offset of the L1 table in the image in bytes. */
117 uint64_t u64L1TableOffset;
118 /** Start of the refcount table in the image. */
119 uint64_t u64RefcountTableOffset;
120 /** Size of the refcount table in clusters. */
121 uint32_t u32RefcountTableClusters;
122 /** Number of snapshots in the image. */
123 uint32_t u32NbSnapshots;
124 /** Offset of the first snapshot header in the image. */
125 uint64_t u64SnapshotsOffset;
[77924]126 /** Version 3 additional data. */
127 struct
128 {
129 /** Incompatible features. */
130 uint64_t u64IncompatFeat;
131 /** Compatible features. */
132 uint64_t u64CompatFeat;
133 /** Autoclear features. */
134 uint64_t u64AutoClrFeat;
135 /** Width in bits of a reference count block. */
136 uint32_t u32RefCntWidth;
137 /** Lenght of the header structure in bytes (for the header extensions). */
138 uint32_t u32HdrLenBytes;
139 } v3;
[38563]140 } v2;
141 } Version;
142} QCowHeader;
143#pragma pack()
144/** Pointer to a on disk QCOW header. */
145typedef QCowHeader *PQCowHeader;
146
147/** QCOW magic value. */
148#define QCOW_MAGIC UINT32_C(0x514649fb) /* QFI\0xfb */
149/** Size of the V1 header. */
150#define QCOW_V1_HDR_SIZE (48)
151/** Size of the V2 header. */
152#define QCOW_V2_HDR_SIZE (72)
153
[38875]154/** Cluster is compressed flag for QCOW images. */
155#define QCOW_V1_COMPRESSED_FLAG RT_BIT_64(63)
156
157/** Copied flag for QCOW2 images. */
158#define QCOW_V2_COPIED_FLAG RT_BIT_64(63)
159/** Cluster is compressed flag for QCOW2 images. */
160#define QCOW_V2_COMPRESSED_FLAG RT_BIT_64(62)
[77921]161/** The mask for extracting the offset from either the L1 or L2 table. */
162#define QCOW_V2_TBL_OFFSET_MASK UINT64_C(0x00fffffffffffe00)
[38875]163
[77924]164/** Incompatible feature: Dirty bit, reference count may be inconsistent. */
165#define QCOW_V3_INCOMPAT_FEAT_F_DIRTY RT_BIT_64(0)
166/** Incompatible feature: Image is corrupt and needs repair. */
167#define QCOW_V3_INCOMPAT_FEAT_F_CORRUPT RT_BIT_64(1)
168/** Incompatible feature: External data file. */
169#define QCOW_V3_INCOMPAT_FEAT_F_EXTERNAL_DATA RT_BIT_64(2)
170/** The incompatible features we support currently. */
171#define QCOW_V3_INCOMPAT_FEAT_SUPPORTED_MASK UINT64_C(0x0)
[38875]172
[77924]173/** Compatible feature: Lazy reference counters. */
174#define QCOW_V3_COMPAT_FEAT_F_LAZY_REF_COUNT RT_BIT_64(0)
175/** The compatible features we support currently. */
176#define QCOW_V3_COMPAT_FEAT_SUPPORTED_MASK UINT64_C(0x0)
177
178/** Auto clear feature: Bitmaps extension. */
179#define QCOW_V3_AUTOCLR_FEAT_F_BITMAPS RT_BIT_64(0)
180/** Auto clear feature: The external data file is raw image which can be accessed standalone. */
181#define QCOW_V3_AUTOCLR_FEAT_F_EXT_RAW_DATA RT_BIT_64(1)
182/** The autoclear features we support currently. */
183#define QCOW_V3_AUTOCLR_FEAT_SUPPORTED_MASK UINT64_C(0x0)
184
185
[57358]186/*********************************************************************************************************************************
187* Constants And Macros, Structures and Typedefs *
188*********************************************************************************************************************************/
[38563]189
190/**
191 * QCOW L2 cache entry.
192 */
193typedef struct QCOWL2CACHEENTRY
194{
195 /** List node for the search list. */
196 RTLISTNODE NodeSearch;
197 /** List node for the LRU list. */
198 RTLISTNODE NodeLru;
199 /** Reference counter. */
200 uint32_t cRefs;
201 /** The offset of the L2 table, used as search key. */
202 uint64_t offL2Tbl;
203 /** Pointer to the cached L2 table. */
204 uint64_t *paL2Tbl;
205} QCOWL2CACHEENTRY, *PQCOWL2CACHEENTRY;
206
207/** Maximum amount of memory the cache is allowed to use. */
208#define QCOW_L2_CACHE_MEMORY_MAX (2*_1M)
209
210/** QCOW default cluster size for image version 2. */
211#define QCOW2_CLUSTER_SIZE_DEFAULT (64*_1K)
212/** QCOW default cluster size for image version 1. */
213#define QCOW_CLUSTER_SIZE_DEFAULT (4*_1K)
214/** QCOW default L2 table size in clusters. */
215#define QCOW_L2_CLUSTERS_DEFAULT (1)
216
217/**
218 * QCOW image data structure.
219 */
220typedef struct QCOWIMAGE
221{
222 /** Image name. */
223 const char *pszFilename;
224 /** Storage handle. */
225 PVDIOSTORAGE pStorage;
226
227 /** Pointer to the per-disk VD interface list. */
228 PVDINTERFACE pVDIfsDisk;
229 /** Pointer to the per-image VD interface list. */
230 PVDINTERFACE pVDIfsImage;
231 /** Error interface. */
232 PVDINTERFACEERROR pIfError;
233 /** I/O interface. */
234 PVDINTERFACEIOINT pIfIo;
235
236 /** Open flags passed by VBoxHD layer. */
237 unsigned uOpenFlags;
238 /** Image flags defined during creation or determined during open. */
239 unsigned uImageFlags;
240 /** Total size of the image. */
241 uint64_t cbSize;
242 /** Physical geometry of this image. */
243 VDGEOMETRY PCHSGeometry;
244 /** Logical geometry of this image. */
245 VDGEOMETRY LCHSGeometry;
246
247 /** Image version. */
248 unsigned uVersion;
249 /** MTime field - used only to preserve value in opened images, unmodified otherwise. */
250 uint32_t MTime;
251
252 /** Filename of the backing file if any. */
253 char *pszBackingFilename;
254 /** Offset of the filename in the image. */
255 uint64_t offBackingFilename;
256 /** Size of the backing filename excluding \0. */
257 uint32_t cbBackingFilename;
258
[38875]259 /** Next offset of a new cluster, aligned to sector size. */
260 uint64_t offNextCluster;
[38563]261 /** Cluster size in bytes. */
262 uint32_t cbCluster;
[82595]263 /** Number of bits in the virtual offset used as the cluster offset. */
264 uint32_t cClusterBits;
265 /** Bitmask to extract the offset from a compressed cluster descriptor. */
266 uint64_t fMaskCompressedClusterOffset;
267 /** Bitmask to extract the sector count from a compressed cluster descriptor. */
268 uint64_t fMaskCompressedClusterSectors;
269 /** Number of bits to shift the sector count to the right to get the final value. */
270 uint32_t cBitsShiftRCompressedClusterSectors;
[38563]271 /** Number of entries in the L1 table. */
272 uint32_t cL1TableEntries;
273 /** Size of an L1 rounded to the next cluster size. */
274 uint32_t cbL1Table;
275 /** Pointer to the L1 table. */
276 uint64_t *paL1Table;
277 /** Offset of the L1 table. */
278 uint64_t offL1Table;
279
280 /** Size of the L2 table in bytes. */
281 uint32_t cbL2Table;
282 /** Number of entries in the L2 table. */
283 uint32_t cL2TableEntries;
284 /** Memory occupied by the L2 table cache. */
285 size_t cbL2Cache;
286 /** The sorted L2 entry list used for searching. */
287 RTLISTNODE ListSearch;
288 /** The LRU L2 entry list used for eviction. */
289 RTLISTNODE ListLru;
290
291 /** Offset of the refcount table. */
292 uint64_t offRefcountTable;
293 /** Size of the refcount table in bytes. */
294 uint32_t cbRefcountTable;
[38875]295 /** Number of entries in the refcount table. */
296 uint32_t cRefcountTableEntries;
297 /** Pointer to the refcount table. */
298 uint64_t *paRefcountTable;
[38563]299
300 /** Offset mask for a cluster. */
301 uint64_t fOffsetMask;
302 /** Number of bits to shift to get the L1 index. */
303 uint32_t cL1Shift;
304 /** L2 table mask to get the L2 index. */
305 uint64_t fL2Mask;
306 /** Number of bits to shift to get the L2 index. */
307 uint32_t cL2Shift;
308
[82595]309 /** Size of compressed cluster buffer. */
310 size_t cbCompCluster;
311 /** Compressed cluster buffer. */
312 void *pvCompCluster;
313 /** Buffer to hold the uncompressed data. */
314 void *pvCluster;
315
[64829]316 /** Pointer to the L2 table we are currently allocating
317 * (can be only one at a time). */
318 PQCOWL2CACHEENTRY pL2TblAlloc;
[66486]319 /** The static region list. */
320 VDREGIONLIST RegionList;
[38563]321} QCOWIMAGE, *PQCOWIMAGE;
322
323/**
324 * State of the async cluster allocation.
325 */
326typedef enum QCOWCLUSTERASYNCALLOCSTATE
327{
328 /** Invalid. */
329 QCOWCLUSTERASYNCALLOCSTATE_INVALID = 0,
330 /** L2 table allocation. */
331 QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC,
332 /** Link L2 table into L1. */
333 QCOWCLUSTERASYNCALLOCSTATE_L2_LINK,
334 /** Allocate user data cluster. */
335 QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC,
336 /** Link user data cluster. */
337 QCOWCLUSTERASYNCALLOCSTATE_USER_LINK,
338 /** 32bit blowup. */
339 QCOWCLUSTERASYNCALLOCSTATE_32BIT_HACK = 0x7fffffff
340} QCOWCLUSTERASYNCALLOCSTATE, *PQCOWCLUSTERASYNCALLOCSTATE;
341
342/**
343 * Data needed to track async cluster allocation.
344 */
345typedef struct QCOWCLUSTERASYNCALLOC
346{
347 /** The state of the cluster allocation. */
348 QCOWCLUSTERASYNCALLOCSTATE enmAllocState;
349 /** Old image size to rollback in case of an error. */
[38875]350 uint64_t offNextClusterOld;
[38563]351 /** L1 index to link if any. */
352 uint32_t idxL1;
353 /** L2 index to link, required in any case. */
354 uint32_t idxL2;
355 /** Start offset of the allocated cluster. */
356 uint64_t offClusterNew;
357 /** L2 cache entry if a L2 table is allocated. */
358 PQCOWL2CACHEENTRY pL2Entry;
359 /** Number of bytes to write. */
360 size_t cbToWrite;
361} QCOWCLUSTERASYNCALLOC, *PQCOWCLUSTERASYNCALLOC;
362
363
[57358]364/*********************************************************************************************************************************
365* Static Variables *
366*********************************************************************************************************************************/
367
[38563]368/** NULL-terminated array of supported file extensions. */
369static const VDFILEEXTENSION s_aQCowFileExtensions[] =
370{
371 {"qcow", VDTYPE_HDD},
372 {"qcow2", VDTYPE_HDD},
373 {NULL, VDTYPE_INVALID}
374};
375
376
[57358]377/*********************************************************************************************************************************
378* Internal Functions *
379*********************************************************************************************************************************/
380
[38563]381/**
382 * Return power of 2 or 0 if num error.
383 *
384 * @returns The power of 2 or 0 if the given number is not a power of 2.
385 * @param u32 The number.
386 */
387static uint32_t qcowGetPowerOfTwo(uint32_t u32)
388{
389 if (u32 == 0)
390 return 0;
391 uint32_t uPower2 = 0;
392 while ((u32 & 1) == 0)
393 {
394 u32 >>= 1;
395 uPower2++;
396 }
397 return u32 == 1 ? uPower2 : 0;
398}
399
400
401/**
402 * Converts the image header to the host endianess and performs basic checks.
403 *
404 * @returns Whether the given header is valid or not.
405 * @param pHeader Pointer to the header to convert.
406 */
407static bool qcowHdrConvertToHostEndianess(PQCowHeader pHeader)
408{
409 pHeader->u32Magic = RT_BE2H_U32(pHeader->u32Magic);
410 pHeader->u32Version = RT_BE2H_U32(pHeader->u32Version);
411
412 if (pHeader->u32Magic != QCOW_MAGIC)
413 return false;
414
415 if (pHeader->u32Version == 1)
416 {
417 pHeader->Version.v1.u64BackingFileOffset = RT_BE2H_U64(pHeader->Version.v1.u64BackingFileOffset);
418 pHeader->Version.v1.u32BackingFileSize = RT_BE2H_U32(pHeader->Version.v1.u32BackingFileSize);
419 pHeader->Version.v1.u32MTime = RT_BE2H_U32(pHeader->Version.v1.u32MTime);
420 pHeader->Version.v1.u64Size = RT_BE2H_U64(pHeader->Version.v1.u64Size);
421 pHeader->Version.v1.u32CryptMethod = RT_BE2H_U32(pHeader->Version.v1.u32CryptMethod);
422 pHeader->Version.v1.u64L1TableOffset = RT_BE2H_U64(pHeader->Version.v1.u64L1TableOffset);
423 }
[77924]424 else if (pHeader->u32Version == 2 || pHeader->u32Version == 3)
[38563]425 {
426 pHeader->Version.v2.u64BackingFileOffset = RT_BE2H_U64(pHeader->Version.v2.u64BackingFileOffset);
427 pHeader->Version.v2.u32BackingFileSize = RT_BE2H_U32(pHeader->Version.v2.u32BackingFileSize);
428 pHeader->Version.v2.u32ClusterBits = RT_BE2H_U32(pHeader->Version.v2.u32ClusterBits);
429 pHeader->Version.v2.u64Size = RT_BE2H_U64(pHeader->Version.v2.u64Size);
430 pHeader->Version.v2.u32CryptMethod = RT_BE2H_U32(pHeader->Version.v2.u32CryptMethod);
431 pHeader->Version.v2.u32L1Size = RT_BE2H_U32(pHeader->Version.v2.u32L1Size);
432 pHeader->Version.v2.u64L1TableOffset = RT_BE2H_U64(pHeader->Version.v2.u64L1TableOffset);
433 pHeader->Version.v2.u64RefcountTableOffset = RT_BE2H_U64(pHeader->Version.v2.u64RefcountTableOffset);
434 pHeader->Version.v2.u32RefcountTableClusters = RT_BE2H_U32(pHeader->Version.v2.u32RefcountTableClusters);
435 pHeader->Version.v2.u32NbSnapshots = RT_BE2H_U32(pHeader->Version.v2.u32NbSnapshots);
436 pHeader->Version.v2.u64SnapshotsOffset = RT_BE2H_U64(pHeader->Version.v2.u64SnapshotsOffset);
[77924]437
438 if (pHeader->u32Version == 3)
439 {
440 pHeader->Version.v2.v3.u64IncompatFeat = RT_BE2H_U64(pHeader->Version.v2.v3.u64IncompatFeat);
441 pHeader->Version.v2.v3.u64CompatFeat = RT_BE2H_U64(pHeader->Version.v2.v3.u64CompatFeat);
442 pHeader->Version.v2.v3.u64AutoClrFeat = RT_BE2H_U64(pHeader->Version.v2.v3.u64AutoClrFeat);
443 pHeader->Version.v2.v3.u32RefCntWidth = RT_BE2H_U32(pHeader->Version.v2.v3.u32RefCntWidth);
444 pHeader->Version.v2.v3.u32HdrLenBytes = RT_BE2H_U32(pHeader->Version.v2.v3.u32HdrLenBytes);
445 }
[38563]446 }
447 else
448 return false;
449
450 return true;
451}
452
453/**
454 * Creates a QCOW header from the given image state.
455 *
456 * @param pImage Image instance data.
457 * @param pHeader Pointer to the header to convert.
458 * @param pcbHeader Where to store the size of the header to write.
459 */
460static void qcowHdrConvertFromHostEndianess(PQCOWIMAGE pImage, PQCowHeader pHeader,
461 size_t *pcbHeader)
462{
463 memset(pHeader, 0, sizeof(QCowHeader));
464
465 pHeader->u32Magic = RT_H2BE_U32(QCOW_MAGIC);
466 pHeader->u32Version = RT_H2BE_U32(pImage->uVersion);
467 if (pImage->uVersion == 1)
468 {
469 pHeader->Version.v1.u64BackingFileOffset = RT_H2BE_U64(pImage->offBackingFilename);
470 pHeader->Version.v1.u32BackingFileSize = RT_H2BE_U32(pImage->cbBackingFilename);
471 pHeader->Version.v1.u32MTime = RT_H2BE_U32(pImage->MTime);
472 pHeader->Version.v1.u64Size = RT_H2BE_U64(pImage->cbSize);
473 pHeader->Version.v1.u8ClusterBits = (uint8_t)qcowGetPowerOfTwo(pImage->cbCluster);
474 pHeader->Version.v1.u8L2Bits = (uint8_t)qcowGetPowerOfTwo(pImage->cL2TableEntries);
475 pHeader->Version.v1.u32CryptMethod = RT_H2BE_U32(0);
476 pHeader->Version.v1.u64L1TableOffset = RT_H2BE_U64(pImage->offL1Table);
477 *pcbHeader = QCOW_V1_HDR_SIZE;
478 }
479 else if (pImage->uVersion == 2)
480 {
481 pHeader->Version.v2.u64BackingFileOffset = RT_H2BE_U64(pImage->offBackingFilename);
482 pHeader->Version.v2.u32BackingFileSize = RT_H2BE_U32(pImage->cbBackingFilename);
[38875]483 pHeader->Version.v2.u32ClusterBits = RT_H2BE_U32(qcowGetPowerOfTwo(pImage->cbCluster));
[38563]484 pHeader->Version.v2.u64Size = RT_H2BE_U64(pImage->cbSize);
485 pHeader->Version.v2.u32CryptMethod = RT_H2BE_U32(0);
486 pHeader->Version.v2.u32L1Size = RT_H2BE_U32(pImage->cL1TableEntries);
487 pHeader->Version.v2.u64L1TableOffset = RT_H2BE_U64(pImage->offL1Table);
488 pHeader->Version.v2.u64RefcountTableOffset = RT_H2BE_U64(pImage->offRefcountTable);
489 pHeader->Version.v2.u32RefcountTableClusters = RT_H2BE_U32(pImage->cbRefcountTable / pImage->cbCluster);
490 pHeader->Version.v2.u32NbSnapshots = RT_H2BE_U32(0);
491 pHeader->Version.v2.u64SnapshotsOffset = RT_H2BE_U64((uint64_t)0);
492 *pcbHeader = QCOW_V2_HDR_SIZE;
493 }
494 else
495 AssertMsgFailed(("Invalid version of the QCOW image format %d\n", pImage->uVersion));
496}
497
498/**
499 * Convert table entries from little endian to host endianess.
500 *
501 * @param paTbl Pointer to the table.
502 * @param cEntries Number of entries in the table.
503 */
504static void qcowTableConvertToHostEndianess(uint64_t *paTbl, uint32_t cEntries)
505{
[99739]506 while (cEntries-- > 0)
[38563]507 {
508 *paTbl = RT_BE2H_U64(*paTbl);
509 paTbl++;
510 }
511}
512
513/**
514 * Convert table entries from host to little endian format.
515 *
516 * @param paTblImg Pointer to the table which will store the little endian table.
517 * @param paTbl The source table to convert.
518 * @param cEntries Number of entries in the table.
519 */
[99739]520static void qcowTableConvertFromHostEndianess(uint64_t *paTblImg, uint64_t const *paTbl,
[38563]521 uint32_t cEntries)
522{
[99739]523 while (cEntries-- > 0)
[38563]524 {
525 *paTblImg = RT_H2BE_U64(*paTbl);
526 paTbl++;
527 paTblImg++;
528 }
529}
530
531/**
532 * Creates the L2 table cache.
533 *
534 * @returns VBox status code.
535 * @param pImage The image instance data.
536 */
537static int qcowL2TblCacheCreate(PQCOWIMAGE pImage)
538{
539 pImage->cbL2Cache = 0;
540 RTListInit(&pImage->ListSearch);
541 RTListInit(&pImage->ListLru);
542
543 return VINF_SUCCESS;
544}
545
546/**
547 * Destroys the L2 table cache.
548 *
549 * @param pImage The image instance data.
550 */
551static void qcowL2TblCacheDestroy(PQCOWIMAGE pImage)
552{
[64766]553 PQCOWL2CACHEENTRY pL2Entry;
554 PQCOWL2CACHEENTRY pL2Next;
[38563]555 RTListForEachSafe(&pImage->ListSearch, pL2Entry, pL2Next, QCOWL2CACHEENTRY, NodeSearch)
556 {
557 Assert(!pL2Entry->cRefs);
558
559 RTListNodeRemove(&pL2Entry->NodeSearch);
560 RTMemPageFree(pL2Entry->paL2Tbl, pImage->cbL2Table);
561 RTMemFree(pL2Entry);
562 }
563
564 pImage->cbL2Cache = 0;
565 RTListInit(&pImage->ListSearch);
566 RTListInit(&pImage->ListLru);
567}
568
569/**
570 * Returns the L2 table matching the given offset or NULL if none could be found.
571 *
572 * @returns Pointer to the L2 table cache entry or NULL.
573 * @param pImage The image instance data.
574 * @param offL2Tbl Offset of the L2 table to search for.
575 */
576static PQCOWL2CACHEENTRY qcowL2TblCacheRetain(PQCOWIMAGE pImage, uint64_t offL2Tbl)
577{
[64829]578 if ( pImage->pL2TblAlloc
579 && pImage->pL2TblAlloc->offL2Tbl == offL2Tbl)
580 {
581 pImage->pL2TblAlloc->cRefs++;
582 return pImage->pL2TblAlloc;
583 }
584
[64766]585 PQCOWL2CACHEENTRY pL2Entry;
[38563]586 RTListForEach(&pImage->ListSearch, pL2Entry, QCOWL2CACHEENTRY, NodeSearch)
587 {
588 if (pL2Entry->offL2Tbl == offL2Tbl)
589 break;
590 }
591
592 if (!RTListNodeIsDummy(&pImage->ListSearch, pL2Entry, QCOWL2CACHEENTRY, NodeSearch))
593 {
594 /* Update LRU list. */
595 RTListNodeRemove(&pL2Entry->NodeLru);
596 RTListPrepend(&pImage->ListLru, &pL2Entry->NodeLru);
597 pL2Entry->cRefs++;
598 return pL2Entry;
599 }
[64766]600
601 return NULL;
[38563]602}
603
604/**
605 * Releases a L2 table cache entry.
606 *
607 * @param pL2Entry The L2 cache entry.
608 */
609static void qcowL2TblCacheEntryRelease(PQCOWL2CACHEENTRY pL2Entry)
610{
611 Assert(pL2Entry->cRefs > 0);
612 pL2Entry->cRefs--;
613}
614
615/**
616 * Allocates a new L2 table from the cache evicting old entries if required.
617 *
618 * @returns Pointer to the L2 cache entry or NULL.
619 * @param pImage The image instance data.
620 */
621static PQCOWL2CACHEENTRY qcowL2TblCacheEntryAlloc(PQCOWIMAGE pImage)
622{
623 PQCOWL2CACHEENTRY pL2Entry = NULL;
624
625 if (pImage->cbL2Cache + pImage->cbL2Table <= QCOW_L2_CACHE_MEMORY_MAX)
626 {
627 /* Add a new entry. */
628 pL2Entry = (PQCOWL2CACHEENTRY)RTMemAllocZ(sizeof(QCOWL2CACHEENTRY));
629 if (pL2Entry)
630 {
631 pL2Entry->paL2Tbl = (uint64_t *)RTMemPageAllocZ(pImage->cbL2Table);
632 if (RT_UNLIKELY(!pL2Entry->paL2Tbl))
633 {
634 RTMemFree(pL2Entry);
635 pL2Entry = NULL;
636 }
637 else
638 {
639 pL2Entry->cRefs = 1;
640 pImage->cbL2Cache += pImage->cbL2Table;
641 }
642 }
643 }
644 else
645 {
646 /* Evict the last not in use entry and use it */
647 Assert(!RTListIsEmpty(&pImage->ListLru));
648
649 RTListForEachReverse(&pImage->ListLru, pL2Entry, QCOWL2CACHEENTRY, NodeLru)
650 {
651 if (!pL2Entry->cRefs)
652 break;
653 }
654
655 if (!RTListNodeIsDummy(&pImage->ListSearch, pL2Entry, QCOWL2CACHEENTRY, NodeSearch))
656 {
657 RTListNodeRemove(&pL2Entry->NodeSearch);
658 RTListNodeRemove(&pL2Entry->NodeLru);
659 pL2Entry->offL2Tbl = 0;
660 pL2Entry->cRefs = 1;
661 }
662 else
663 pL2Entry = NULL;
664 }
665
666 return pL2Entry;
667}
668
669/**
670 * Frees a L2 table cache entry.
671 *
672 * @param pImage The image instance data.
673 * @param pL2Entry The L2 cache entry to free.
674 */
675static void qcowL2TblCacheEntryFree(PQCOWIMAGE pImage, PQCOWL2CACHEENTRY pL2Entry)
676{
677 Assert(!pL2Entry->cRefs);
678 RTMemPageFree(pL2Entry->paL2Tbl, pImage->cbL2Table);
679 RTMemFree(pL2Entry);
680
681 pImage->cbL2Cache -= pImage->cbL2Table;
682}
683
684/**
685 * Inserts an entry in the L2 table cache.
686 *
687 * @param pImage The image instance data.
688 * @param pL2Entry The L2 cache entry to insert.
689 */
690static void qcowL2TblCacheEntryInsert(PQCOWIMAGE pImage, PQCOWL2CACHEENTRY pL2Entry)
691{
692 Assert(pL2Entry->offL2Tbl > 0);
693
694 /* Insert at the top of the LRU list. */
695 RTListPrepend(&pImage->ListLru, &pL2Entry->NodeLru);
696
697 if (RTListIsEmpty(&pImage->ListSearch))
698 {
699 RTListAppend(&pImage->ListSearch, &pL2Entry->NodeSearch);
700 }
701 else
702 {
703 /* Insert into search list. */
[64766]704 PQCOWL2CACHEENTRY pIt;
[38563]705 pIt = RTListGetFirst(&pImage->ListSearch, QCOWL2CACHEENTRY, NodeSearch);
706 if (pIt->offL2Tbl > pL2Entry->offL2Tbl)
707 RTListPrepend(&pImage->ListSearch, &pL2Entry->NodeSearch);
708 else
709 {
710 bool fInserted = false;
711
712 RTListForEach(&pImage->ListSearch, pIt, QCOWL2CACHEENTRY, NodeSearch)
713 {
714 Assert(pIt->offL2Tbl != pL2Entry->offL2Tbl);
715 if (pIt->offL2Tbl < pL2Entry->offL2Tbl)
716 {
717 RTListNodeInsertAfter(&pIt->NodeSearch, &pL2Entry->NodeSearch);
718 fInserted = true;
719 break;
720 }
721 }
[64766]722 Assert(fInserted);
[38563]723 }
724 }
725}
726
727/**
728 * Fetches the L2 from the given offset trying the LRU cache first and
729 * reading it from the image after a cache miss.
730 *
731 * @returns VBox status code.
732 * @param pImage Image instance data.
733 * @param pIoCtx The I/O context.
734 * @param offL2Tbl The offset of the L2 table in the image.
735 * @param ppL2Entry Where to store the L2 table on success.
736 */
[44252]737static int qcowL2TblCacheFetch(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, uint64_t offL2Tbl,
738 PQCOWL2CACHEENTRY *ppL2Entry)
[38563]739{
740 int rc = VINF_SUCCESS;
741
742 /* Try to fetch the L2 table from the cache first. */
743 PQCOWL2CACHEENTRY pL2Entry = qcowL2TblCacheRetain(pImage, offL2Tbl);
744 if (!pL2Entry)
745 {
746 pL2Entry = qcowL2TblCacheEntryAlloc(pImage);
747
748 if (pL2Entry)
749 {
750 /* Read from the image. */
751 PVDMETAXFER pMetaXfer;
752
753 pL2Entry->offL2Tbl = offL2Tbl;
[44233]754 rc = vdIfIoIntFileReadMeta(pImage->pIfIo, pImage->pStorage,
755 offL2Tbl, pL2Entry->paL2Tbl,
756 pImage->cbL2Table, pIoCtx,
757 &pMetaXfer, NULL, NULL);
[38563]758 if (RT_SUCCESS(rc))
759 {
760 vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer);
761#if defined(RT_LITTLE_ENDIAN)
762 qcowTableConvertToHostEndianess(pL2Entry->paL2Tbl, pImage->cL2TableEntries);
763#endif
764 qcowL2TblCacheEntryInsert(pImage, pL2Entry);
765 }
766 else
767 {
768 qcowL2TblCacheEntryRelease(pL2Entry);
769 qcowL2TblCacheEntryFree(pImage, pL2Entry);
770 }
771 }
772 else
773 rc = VERR_NO_MEMORY;
774 }
775
776 if (RT_SUCCESS(rc))
777 *ppL2Entry = pL2Entry;
778
779 return rc;
780}
781
782/**
783 * Sets the L1, L2 and offset bitmasks and L1 and L2 bit shift members.
784 *
785 * @param pImage The image instance data.
786 */
787static void qcowTableMasksInit(PQCOWIMAGE pImage)
788{
789 uint32_t cClusterBits, cL2TableBits;
790
791 cClusterBits = qcowGetPowerOfTwo(pImage->cbCluster);
792 cL2TableBits = qcowGetPowerOfTwo(pImage->cL2TableEntries);
793
794 Assert(cClusterBits + cL2TableBits < 64);
795
796 pImage->fOffsetMask = ((uint64_t)pImage->cbCluster - 1);
797 pImage->fL2Mask = ((uint64_t)pImage->cL2TableEntries - 1) << cClusterBits;
798 pImage->cL2Shift = cClusterBits;
799 pImage->cL1Shift = cClusterBits + cL2TableBits;
800}
801
802/**
[40106]803 * Converts a given logical offset into the
[38563]804 *
805 * @param pImage The image instance data.
806 * @param off The logical offset to convert.
807 * @param pidxL1 Where to store the index in the L1 table on success.
808 * @param pidxL2 Where to store the index in the L2 table on success.
809 * @param poffCluster Where to store the offset in the cluster on success.
810 */
811DECLINLINE(void) qcowConvertLogicalOffset(PQCOWIMAGE pImage, uint64_t off, uint32_t *pidxL1,
812 uint32_t *pidxL2, uint32_t *poffCluster)
813{
814 AssertPtr(pidxL1);
815 AssertPtr(pidxL2);
816 AssertPtr(poffCluster);
817
818 *poffCluster = off & pImage->fOffsetMask;
819 *pidxL1 = off >> pImage->cL1Shift;
820 *pidxL2 = (off & pImage->fL2Mask) >> pImage->cL2Shift;
821}
822
823/**
824 * Converts Cluster size to a byte size.
825 *
826 * @returns Number of bytes derived from the given number of clusters.
827 * @param pImage The image instance data.
828 * @param cClusters The clusters to convert.
829 */
830DECLINLINE(uint64_t) qcowCluster2Byte(PQCOWIMAGE pImage, uint64_t cClusters)
831{
832 return cClusters * pImage->cbCluster;
833}
834
835/**
836 * Converts number of bytes to cluster size rounding to the next cluster.
837 *
838 * @returns Number of bytes derived from the given number of clusters.
839 * @param pImage The image instance data.
840 * @param cb Number of bytes to convert.
841 */
842DECLINLINE(uint64_t) qcowByte2Cluster(PQCOWIMAGE pImage, uint64_t cb)
843{
844 return cb / pImage->cbCluster + (cb % pImage->cbCluster ? 1 : 0);
845}
846
847/**
848 * Allocates a new cluster in the image.
849 *
850 * @returns The start offset of the new cluster in the image.
851 * @param pImage The image instance data.
[64272]852 * @param cClusters Number of clusters to allocate.
[38563]853 */
854DECLINLINE(uint64_t) qcowClusterAllocate(PQCOWIMAGE pImage, uint32_t cClusters)
855{
856 uint64_t offCluster;
857
[38875]858 offCluster = pImage->offNextCluster;
859 pImage->offNextCluster += cClusters*pImage->cbCluster;
[38563]860
861 return offCluster;
862}
863
864/**
865 * Returns the real image offset for a given cluster or an error if the cluster is not
866 * yet allocated.
867 *
868 * @returns VBox status code.
869 * VERR_VD_BLOCK_FREE if the cluster is not yet allocated.
870 * @param pImage The image instance data.
[44252]871 * @param pIoCtx The I/O context.
[38563]872 * @param idxL1 The L1 index.
873 * @param idxL2 The L2 index.
874 * @param offCluster Offset inside the cluster.
[82596]875 * @param poffImage Where to store the image offset on success.
876 * @param pfCompressed Where to store the flag whether the cluster is compressed on success.
877 * @param pcbCompressed Where to store the size of the compressed cluster in bytes on success.
878 * Only valid when the cluster comrpessed flag is true.
[38563]879 */
[44252]880static int qcowConvertToImageOffset(PQCOWIMAGE pImage, PVDIOCTX pIoCtx,
881 uint32_t idxL1, uint32_t idxL2,
[82595]882 uint32_t offCluster, uint64_t *poffImage,
883 bool *pfCompressed, size_t *pcbCompressed)
[38563]884{
885 int rc = VERR_VD_BLOCK_FREE;
886
887 AssertReturn(idxL1 < pImage->cL1TableEntries, VERR_INVALID_PARAMETER);
888 AssertReturn(idxL2 < pImage->cL2TableEntries, VERR_INVALID_PARAMETER);
889
890 if (pImage->paL1Table[idxL1])
891 {
892 PQCOWL2CACHEENTRY pL2Entry;
893
[77921]894 uint64_t offL2Tbl = pImage->paL1Table[idxL1];
895 if (pImage->uVersion == 2)
896 offL2Tbl &= QCOW_V2_TBL_OFFSET_MASK;
897 rc = qcowL2TblCacheFetch(pImage, pIoCtx, offL2Tbl, &pL2Entry);
[38563]898 if (RT_SUCCESS(rc))
899 {
900 /* Get real file offset. */
901 if (pL2Entry->paL2Tbl[idxL2])
[38875]902 {
903 uint64_t off = pL2Entry->paL2Tbl[idxL2];
904
905 /* Strip flags */
906 if (pImage->uVersion == 2)
907 {
908 if (RT_UNLIKELY(off & QCOW_V2_COMPRESSED_FLAG))
[82595]909 {
910 size_t cCompressedClusterSectors = ((off & pImage->fMaskCompressedClusterSectors) >> pImage->cBitsShiftRCompressedClusterSectors);
911 uint64_t offImage = off & pImage->fMaskCompressedClusterOffset;
912
913 *pfCompressed = true;
914 *poffImage = offImage;
915 *pcbCompressed = (cCompressedClusterSectors + 1) * 512 - (offImage & 511ULL);
916 }
[38875]917 else
[82595]918 {
[77921]919 off &= QCOW_V2_TBL_OFFSET_MASK;
[82595]920
921 *pfCompressed = false;
922 *poffImage = off + offCluster;
923 }
[38875]924 }
925 else
926 {
927 if (RT_UNLIKELY(off & QCOW_V1_COMPRESSED_FLAG))
[82595]928 {
929 size_t cCompressedClusterSectors = (off & pImage->fMaskCompressedClusterSectors) >> pImage->cBitsShiftRCompressedClusterSectors;
930
931 *pfCompressed = true;
932 *poffImage = off & pImage->fMaskCompressedClusterOffset;
933 *pcbCompressed = cCompressedClusterSectors * 512; /* Only additional sectors */
934 /* Add remaining bytes of the sector the offset starts in. */
935 *pcbCompressed += 512 - RT_ALIGN_64(*poffImage, 512) - *poffImage;
936 }
[38875]937 else
[82595]938 {
[38875]939 off &= ~QCOW_V1_COMPRESSED_FLAG;
[82595]940
941 *pfCompressed = false;
942 *poffImage = off + offCluster;
943 }
[38875]944 }
945 }
[38563]946 else
947 rc = VERR_VD_BLOCK_FREE;
948
949 qcowL2TblCacheEntryRelease(pL2Entry);
950 }
951 }
952
953 return rc;
954}
955
[63741]956/**
957 * Write the given table to image converting to the image endianess if required.
958 *
959 * @returns VBox status code.
960 * @param pImage The image instance data.
961 * @param pIoCtx The I/O context.
962 * @param offTbl The offset the table should be written to.
963 * @param paTbl The table to write.
[64272]964 * @param cbTbl Size of the table in bytes.
965 * @param cTblEntries Number entries in the table.
[63741]966 * @param pfnComplete Callback called when the write completes.
967 * @param pvUser Opaque user data to pass in the completion callback.
968 */
969static int qcowTblWrite(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, uint64_t offTbl, uint64_t *paTbl,
970 size_t cbTbl, unsigned cTblEntries,
971 PFNVDXFERCOMPLETED pfnComplete, void *pvUser)
972{
973 int rc = VINF_SUCCESS;
[38563]974
[63741]975#if defined(RT_LITTLE_ENDIAN)
976 uint64_t *paTblImg = (uint64_t *)RTMemAllocZ(cbTbl);
977 if (paTblImg)
978 {
979 qcowTableConvertFromHostEndianess(paTblImg, paTbl, cTblEntries);
980 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
981 offTbl, paTblImg, cbTbl,
982 pIoCtx, pfnComplete, pvUser);
983 RTMemFree(paTblImg);
984 }
985 else
986 rc = VERR_NO_MEMORY;
987#else
988 /* Write table directly. */
989 RT_NOREF(cTblEntries);
990 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
991 offTbl, paTbl, cbTbl, pIoCtx,
992 pfnComplete, pvUser);
993#endif
994
995 return rc;
996}
997
[38563]998/**
999 * Internal. Flush image data to disk.
1000 */
1001static int qcowFlushImage(PQCOWIMAGE pImage)
1002{
1003 int rc = VINF_SUCCESS;
1004
1005 if ( pImage->pStorage
[38875]1006 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1007 && pImage->cbL1Table)
[38563]1008 {
1009 QCowHeader Header;
1010
1011#if defined(RT_LITTLE_ENDIAN)
1012 uint64_t *paL1TblImg = (uint64_t *)RTMemAllocZ(pImage->cbL1Table);
1013 if (paL1TblImg)
1014 {
1015 qcowTableConvertFromHostEndianess(paL1TblImg, pImage->paL1Table,
1016 pImage->cL1TableEntries);
1017 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
1018 pImage->offL1Table, paL1TblImg,
[44233]1019 pImage->cbL1Table);
[38563]1020 RTMemFree(paL1TblImg);
1021 }
1022 else
1023 rc = VERR_NO_MEMORY;
1024#else
1025 /* Write L1 table directly. */
1026 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->offL1Table,
[44233]1027 pImage->paL1Table, pImage->cbL1Table);
[38563]1028#endif
1029 if (RT_SUCCESS(rc))
1030 {
1031 /* Write header. */
1032 size_t cbHeader = 0;
1033 qcowHdrConvertFromHostEndianess(pImage, &Header, &cbHeader);
1034 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0, &Header,
[44233]1035 cbHeader);
[38563]1036 if (RT_SUCCESS(rc))
1037 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
1038 }
1039 }
1040
1041 return rc;
1042}
1043
1044/**
1045 * Internal. Free all allocated space for representing an image except pImage,
1046 * and optionally delete the image from disk.
1047 */
1048static int qcowFreeImage(PQCOWIMAGE pImage, bool fDelete)
1049{
1050 int rc = VINF_SUCCESS;
1051
1052 /* Freeing a never allocated image (e.g. because the open failed) is
1053 * not signalled as an error. After all nothing bad happens. */
1054 if (pImage)
1055 {
1056 if (pImage->pStorage)
1057 {
1058 /* No point updating the file that is deleted anyway. */
1059 if (!fDelete)
1060 qcowFlushImage(pImage);
1061
[46613]1062 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
[38563]1063 pImage->pStorage = NULL;
1064 }
1065
[77921]1066 if (pImage->paRefcountTable)
1067 RTMemFree(pImage->paRefcountTable);
1068 pImage->paRefcountTable = NULL;
1069
[38563]1070 if (pImage->paL1Table)
1071 RTMemFree(pImage->paL1Table);
1072
1073 if (pImage->pszBackingFilename)
[44940]1074 {
[77232]1075 RTStrFree(pImage->pszBackingFilename);
[44940]1076 pImage->pszBackingFilename = NULL;
1077 }
[38563]1078
[82595]1079 if (pImage->pvCompCluster)
1080 {
1081 RTMemFree(pImage->pvCompCluster);
1082 pImage->pvCompCluster = NULL;
1083 pImage->cbCompCluster = 0;
1084 }
1085
1086 if (pImage->pvCluster)
1087 {
1088 RTMemFree(pImage->pvCluster);
1089 pImage->pvCluster = NULL;
1090 }
1091
[38563]1092 qcowL2TblCacheDestroy(pImage);
1093
1094 if (fDelete && pImage->pszFilename)
1095 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
1096 }
1097
1098 LogFlowFunc(("returns %Rrc\n", rc));
1099 return rc;
1100}
1101
1102/**
[63635]1103 * Validates the header.
1104 *
1105 * @returns VBox status code.
1106 * @param pImage Image backend instance data.
1107 * @param pHdr The header to validate.
1108 * @param cbFile The image file size in bytes.
1109 */
1110static int qcowHdrValidate(PQCOWIMAGE pImage, PQCowHeader pHdr, uint64_t cbFile)
1111{
1112 if (pHdr->u32Version == 1)
1113 {
1114 /* Check that the backing filename is contained in the file. */
1115 if (pHdr->Version.v1.u64BackingFileOffset + pHdr->Version.v1.u32BackingFileSize > cbFile)
1116 return vdIfError(pImage->pIfError, VERR_INVALID_STATE, RT_SRC_POS,
1117 N_("QCOW: Backing file offset and size exceed size of image '%s' (%u vs %u)"),
1118 pImage->pszFilename, pHdr->Version.v1.u64BackingFileOffset + pHdr->Version.v1.u32BackingFileSize,
1119 cbFile);
1120
1121 /* Check that the cluster bits indicate at least a 512byte sector size. */
1122 if (RT_BIT_32(pHdr->Version.v1.u8ClusterBits) < 512)
1123 return vdIfError(pImage->pIfError, VERR_INVALID_STATE, RT_SRC_POS,
1124 N_("QCOW: Cluster size is too small for image '%s' (%u vs %u)"),
1125 pImage->pszFilename, RT_BIT_32(pHdr->Version.v1.u8ClusterBits), 512);
1126
1127 /*
1128 * Check for possible overflow when multiplying cluster size and L2 entry count because it is used
1129 * to calculate the number of L1 table entries later on.
1130 */
1131 if (RT_BIT_32(pHdr->Version.v1.u8L2Bits) * RT_BIT_32(pHdr->Version.v1.u8ClusterBits) == 0)
1132 return vdIfError(pImage->pIfError, VERR_INVALID_STATE, RT_SRC_POS,
1133 N_("QCOW: Overflow during L1 table size calculation for image '%s'"),
1134 pImage->pszFilename);
1135 }
[77924]1136 else if (pHdr->u32Version == 2 || pHdr->u32Version == 3)
[63635]1137 {
1138 /* Check that the backing filename is contained in the file. */
1139 if (pHdr->Version.v2.u64BackingFileOffset + pHdr->Version.v2.u32BackingFileSize > cbFile)
1140 return vdIfError(pImage->pIfError, VERR_INVALID_STATE, RT_SRC_POS,
1141 N_("QCOW: Backing file offset and size exceed size of image '%s' (%u vs %u)"),
1142 pImage->pszFilename, pHdr->Version.v2.u64BackingFileOffset + pHdr->Version.v2.u32BackingFileSize,
1143 cbFile);
1144
1145 /* Check that the cluster bits indicate at least a 512byte sector size. */
1146 if (RT_BIT_32(pHdr->Version.v2.u32ClusterBits) < 512)
1147 return vdIfError(pImage->pIfError, VERR_INVALID_STATE, RT_SRC_POS,
1148 N_("QCOW: Cluster size is too small for image '%s' (%u vs %u)"),
1149 pImage->pszFilename, RT_BIT_32(pHdr->Version.v2.u32ClusterBits), 512);
[77924]1150
1151 /* Some additional checks for v3 images. */
1152 if (pHdr->u32Version == 3)
1153 {
1154 if (pHdr->Version.v2.v3.u32RefCntWidth > 6)
1155 return vdIfError(pImage->pIfError, VERR_INVALID_STATE, RT_SRC_POS,
1156 N_("QCOW: Reference count width too big for image '%s' (%u vs %u)"),
1157 pImage->pszFilename, RT_BIT_32(pHdr->Version.v2.v3.u32RefCntWidth), 6);
1158 }
[63635]1159 }
1160 else
1161 return vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1162 N_("QCOW: Version %u in image '%s' is not supported"),
1163 pHdr->u32Version, pImage->pszFilename);
1164
1165 return VINF_SUCCESS;
1166}
1167
1168/**
[38563]1169 * Internal: Open an image, constructing all necessary data structures.
1170 */
1171static int qcowOpenImage(PQCOWIMAGE pImage, unsigned uOpenFlags)
1172{
1173 pImage->uOpenFlags = uOpenFlags;
1174
1175 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
1176 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
1177 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
1178
[63793]1179 int rc = qcowL2TblCacheCreate(pImage);
1180 if (RT_SUCCESS(rc))
[38563]1181 {
[63793]1182 /* Open the image. */
1183 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
1184 VDOpenFlagsToFileOpenFlags(uOpenFlags,
1185 false /* fCreate */),
1186 &pImage->pStorage);
1187 if (RT_SUCCESS(rc))
[38563]1188 {
[63793]1189 uint64_t cbFile;
1190 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
1191 if ( RT_SUCCESS(rc)
1192 && cbFile > sizeof(QCowHeader))
1193 {
1194 QCowHeader Header;
[38563]1195
[63793]1196 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0, &Header, sizeof(Header));
1197 if ( RT_SUCCESS(rc)
1198 && qcowHdrConvertToHostEndianess(&Header))
[38563]1199 {
[63793]1200 pImage->offNextCluster = RT_ALIGN_64(cbFile, 512); /* Align image to sector boundary. */
1201 Assert(pImage->offNextCluster >= cbFile);
1202
1203 rc = qcowHdrValidate(pImage, &Header, cbFile);
1204 if (RT_SUCCESS(rc))
[63635]1205 {
[63793]1206 if (Header.u32Version == 1)
1207 {
1208 if (!Header.Version.v1.u32CryptMethod)
1209 {
1210 pImage->uVersion = 1;
1211 pImage->offBackingFilename = Header.Version.v1.u64BackingFileOffset;
1212 pImage->cbBackingFilename = Header.Version.v1.u32BackingFileSize;
1213 pImage->MTime = Header.Version.v1.u32MTime;
1214 pImage->cbSize = Header.Version.v1.u64Size;
[82595]1215 pImage->cClusterBits = Header.Version.v1.u8ClusterBits;
[63793]1216 pImage->cbCluster = RT_BIT_32(Header.Version.v1.u8ClusterBits);
1217 pImage->cL2TableEntries = RT_BIT_32(Header.Version.v1.u8L2Bits);
1218 pImage->cbL2Table = RT_ALIGN_64(pImage->cL2TableEntries * sizeof(uint64_t), pImage->cbCluster);
1219 pImage->offL1Table = Header.Version.v1.u64L1TableOffset;
1220 pImage->cL1TableEntries = pImage->cbSize / (pImage->cbCluster * pImage->cL2TableEntries);
1221 if (pImage->cbSize % (pImage->cbCluster * pImage->cL2TableEntries))
1222 pImage->cL1TableEntries++;
1223 }
1224 else
1225 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1226 N_("QCow: Encrypted image '%s' is not supported"),
1227 pImage->pszFilename);
1228 }
[77924]1229 else if (Header.u32Version == 2 || Header.u32Version == 3)
[63793]1230 {
1231 if (Header.Version.v2.u32CryptMethod)
1232 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1233 N_("QCow: Encrypted image '%s' is not supported"),
1234 pImage->pszFilename);
1235 else if (Header.Version.v2.u32NbSnapshots)
1236 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1237 N_("QCow: Image '%s' contains snapshots which is not supported"),
1238 pImage->pszFilename);
1239 else
1240 {
1241 pImage->uVersion = 2;
1242 pImage->offBackingFilename = Header.Version.v2.u64BackingFileOffset;
1243 pImage->cbBackingFilename = Header.Version.v2.u32BackingFileSize;
1244 pImage->cbSize = Header.Version.v2.u64Size;
[82595]1245 pImage->cClusterBits = Header.Version.v2.u32ClusterBits;
[63793]1246 pImage->cbCluster = RT_BIT_32(Header.Version.v2.u32ClusterBits);
1247 pImage->cL2TableEntries = pImage->cbCluster / sizeof(uint64_t);
1248 pImage->cbL2Table = pImage->cbCluster;
1249 pImage->offL1Table = Header.Version.v2.u64L1TableOffset;
1250 pImage->cL1TableEntries = Header.Version.v2.u32L1Size;
1251 pImage->offRefcountTable = Header.Version.v2.u64RefcountTableOffset;
1252 pImage->cbRefcountTable = qcowCluster2Byte(pImage, Header.Version.v2.u32RefcountTableClusters);
1253 pImage->cRefcountTableEntries = pImage->cbRefcountTable / sizeof(uint64_t);
[77924]1254
[82595]1255 /* Init the masks to extract offset and sector count from a compressed cluster descriptor. */
1256 uint32_t cBitsCompressedClusterOffset = 62 - (pImage->cClusterBits - 8);
1257 pImage->fMaskCompressedClusterOffset = RT_BIT_64(cBitsCompressedClusterOffset) - 1;
1258 pImage->fMaskCompressedClusterSectors = (RT_BIT_64(62) - 1) & ~pImage->fMaskCompressedClusterOffset;
1259 pImage->cBitsShiftRCompressedClusterSectors = cBitsCompressedClusterOffset;
1260
[77924]1261 if (Header.u32Version == 3)
1262 {
1263 if (Header.Version.v2.v3.u64IncompatFeat & ~QCOW_V3_INCOMPAT_FEAT_SUPPORTED_MASK)
1264 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1265 N_("QCow: Image '%s' contains unsupported incompatible features (%llx vs %llx)"),
1266 pImage->pszFilename, Header.Version.v2.v3.u64IncompatFeat, QCOW_V3_INCOMPAT_FEAT_SUPPORTED_MASK);
1267
1268 /** @todo Auto clear features need to be reset as soon as write support is added. */
1269 }
[63793]1270 }
1271 }
1272 else
1273 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1274 N_("QCow: Image '%s' uses version %u which is not supported"),
1275 pImage->pszFilename, Header.u32Version);
1276
[77924]1277 if (RT_SUCCESS(rc))
1278 {
1279 pImage->cbL1Table = RT_ALIGN_64(pImage->cL1TableEntries * sizeof(uint64_t), pImage->cbCluster);
1280 if ((uint64_t)pImage->cbL1Table != RT_ALIGN_64(pImage->cL1TableEntries * sizeof(uint64_t), pImage->cbCluster))
1281 rc = vdIfError(pImage->pIfError, VERR_INVALID_STATE, RT_SRC_POS,
1282 N_("QCOW: L1 table size overflow in image '%s'"),
1283 pImage->pszFilename);
1284 }
[63635]1285 }
[63793]1286
1287 /** @todo Check that there are no compressed clusters in the image
1288 * (by traversing the L2 tables and checking each offset).
1289 * Refuse to open such images.
1290 */
1291
1292 if ( RT_SUCCESS(rc)
1293 && pImage->cbBackingFilename
1294 && pImage->offBackingFilename)
[63635]1295 {
[63793]1296 /* Load backing filename from image. */
[77232]1297 pImage->pszBackingFilename = RTStrAlloc(pImage->cbBackingFilename + 1); /* +1 for \0 terminator. */
[63793]1298 if (pImage->pszBackingFilename)
1299 {
[77232]1300 RT_BZERO(pImage->pszBackingFilename, pImage->cbBackingFilename + 1);
[63793]1301 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
1302 pImage->offBackingFilename, pImage->pszBackingFilename,
1303 pImage->cbBackingFilename);
[77232]1304 if (RT_SUCCESS(rc))
1305 rc = RTStrValidateEncoding(pImage->pszBackingFilename);
[63793]1306 }
1307 else
[77232]1308 rc = VERR_NO_STR_MEMORY;
[63635]1309 }
1310
[63793]1311 if ( RT_SUCCESS(rc)
1312 && pImage->cbRefcountTable
1313 && pImage->offRefcountTable)
1314 {
1315 /* Load refcount table. */
1316 Assert(pImage->cRefcountTableEntries);
1317 pImage->paRefcountTable = (uint64_t *)RTMemAllocZ(pImage->cbRefcountTable);
1318 if (RT_LIKELY(pImage->paRefcountTable))
1319 {
1320 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
1321 pImage->offRefcountTable, pImage->paRefcountTable,
1322 pImage->cbRefcountTable);
1323 if (RT_SUCCESS(rc))
1324 qcowTableConvertToHostEndianess(pImage->paRefcountTable,
1325 pImage->cRefcountTableEntries);
1326 else
1327 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1328 N_("QCow: Reading refcount table of image '%s' failed"),
1329 pImage->pszFilename);
1330 }
1331 else
1332 rc = vdIfError(pImage->pIfError, VERR_NO_MEMORY, RT_SRC_POS,
1333 N_("QCow: Allocating memory for refcount table of image '%s' failed"),
1334 pImage->pszFilename);
1335 }
[38563]1336
[38875]1337 if (RT_SUCCESS(rc))
[63793]1338 {
1339 qcowTableMasksInit(pImage);
[38563]1340
[63793]1341 /* Allocate L1 table. */
1342 pImage->paL1Table = (uint64_t *)RTMemAllocZ(pImage->cbL1Table);
1343 if (pImage->paL1Table)
1344 {
1345 /* Read from the image. */
1346 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
1347 pImage->offL1Table, pImage->paL1Table,
1348 pImage->cbL1Table);
1349 if (RT_SUCCESS(rc))
1350 qcowTableConvertToHostEndianess(pImage->paL1Table, pImage->cL1TableEntries);
1351 else
1352 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1353 N_("QCow: Reading the L1 table for image '%s' failed"),
1354 pImage->pszFilename);
1355 }
1356 else
1357 rc = vdIfError(pImage->pIfError, VERR_NO_MEMORY, RT_SRC_POS,
1358 N_("QCow: Out of memory allocating L1 table for image '%s'"),
1359 pImage->pszFilename);
1360 }
[38563]1361 }
[63793]1362 else if (RT_SUCCESS(rc))
1363 rc = VERR_VD_GEN_INVALID_HEADER;
[38563]1364 }
[63793]1365 else if (RT_SUCCESS(rc))
1366 rc = VERR_VD_GEN_INVALID_HEADER;
[38563]1367 }
[63793]1368 /* else: Do NOT signal an appropriate error here, as the VD layer has the
1369 * choice of retrying the open if it failed. */
[38563]1370 }
1371 else
[63793]1372 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1373 N_("Qcow: Creating the L2 table cache for image '%s' failed"),
1374 pImage->pszFilename);
[38563]1375
[66486]1376 if (RT_SUCCESS(rc))
1377 {
1378 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
1379 pImage->RegionList.fFlags = 0;
1380 pImage->RegionList.cRegions = 1;
1381
1382 pRegion->offRegion = 0; /* Disk start. */
1383 pRegion->cbBlock = 512;
1384 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
1385 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
1386 pRegion->cbData = 512;
1387 pRegion->cbMetadata = 0;
1388 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
1389 }
1390 else
[38563]1391 qcowFreeImage(pImage, false);
1392 return rc;
1393}
1394
1395/**
1396 * Internal: Create a qcow image.
1397 */
1398static int qcowCreateImage(PQCOWIMAGE pImage, uint64_t cbSize,
1399 unsigned uImageFlags, const char *pszComment,
1400 PCVDGEOMETRY pPCHSGeometry,
1401 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
[63793]1402 PVDINTERFACEPROGRESS pIfProgress,
[38563]1403 unsigned uPercentStart, unsigned uPercentSpan)
1404{
[62744]1405 RT_NOREF1(pszComment);
[38563]1406 int rc;
1407 int32_t fOpen;
1408
[63793]1409 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
[38563]1410 {
[63793]1411 rc = qcowL2TblCacheCreate(pImage);
1412 if (RT_SUCCESS(rc))
1413 {
1414 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
1415 pImage->uImageFlags = uImageFlags;
1416 pImage->PCHSGeometry = *pPCHSGeometry;
1417 pImage->LCHSGeometry = *pLCHSGeometry;
1418 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
1419 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
1420 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
[38563]1421
[63793]1422 /* Create image file. */
1423 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
1424 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
1425 if (RT_SUCCESS(rc))
1426 {
1427 /* Init image state. */
1428 pImage->uVersion = 1; /* We create only version 1 images at the moment. */
1429 pImage->cbSize = cbSize;
1430 pImage->cbCluster = QCOW_CLUSTER_SIZE_DEFAULT;
1431 pImage->cbL2Table = qcowCluster2Byte(pImage, QCOW_L2_CLUSTERS_DEFAULT);
1432 pImage->cL2TableEntries = pImage->cbL2Table / sizeof(uint64_t);
[70961]1433 pImage->cL1TableEntries = cbSize / (pImage->cbCluster * pImage->cL2TableEntries);
[63793]1434 if (cbSize % (pImage->cbCluster * pImage->cL2TableEntries))
1435 pImage->cL1TableEntries++;
[70848]1436 pImage->cbL1Table = RT_ALIGN_64(pImage->cL1TableEntries * sizeof(uint64_t), pImage->cbCluster);
[63793]1437 pImage->offL1Table = QCOW_V1_HDR_SIZE;
1438 pImage->cbBackingFilename = 0;
1439 pImage->offBackingFilename = 0;
1440 pImage->offNextCluster = RT_ALIGN_64(QCOW_V1_HDR_SIZE + pImage->cbL1Table, pImage->cbCluster);
1441 qcowTableMasksInit(pImage);
[38563]1442
[63793]1443 /* Init L1 table. */
1444 pImage->paL1Table = (uint64_t *)RTMemAllocZ(pImage->cbL1Table);
1445 if (RT_LIKELY(pImage->paL1Table))
1446 {
1447 if (RT_SUCCESS(rc))
1448 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 98 / 100);
[38563]1449
[63793]1450 rc = qcowFlushImage(pImage);
1451 if (RT_SUCCESS(rc))
1452 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->offNextCluster);
1453 }
1454 else
1455 rc = vdIfError(pImage->pIfError, VERR_NO_MEMORY, RT_SRC_POS, N_("QCow: cannot allocate memory for L1 table of image '%s'"),
1456 pImage->pszFilename);
1457 }
1458 else
1459 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("QCow: cannot create image '%s'"), pImage->pszFilename);
1460 }
1461 else
1462 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("QCow: Failed to create L2 cache for image '%s'"),
1463 pImage->pszFilename);
[38563]1464 }
[63793]1465 else
1466 rc = vdIfError(pImage->pIfError, VERR_VD_INVALID_TYPE, RT_SRC_POS, N_("QCow: cannot create fixed image '%s'"), pImage->pszFilename);
[38563]1467
1468 if (RT_SUCCESS(rc))
[63793]1469 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan);
[38563]1470
[66486]1471 if (RT_SUCCESS(rc))
1472 {
1473 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
1474 pImage->RegionList.fFlags = 0;
1475 pImage->RegionList.cRegions = 1;
1476
1477 pRegion->offRegion = 0; /* Disk start. */
1478 pRegion->cbBlock = 512;
1479 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
1480 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
1481 pRegion->cbData = 512;
1482 pRegion->cbMetadata = 0;
1483 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
1484 }
1485 else
[38563]1486 qcowFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
1487 return rc;
1488}
1489
1490/**
1491 * Rollback anything done during async cluster allocation.
1492 *
1493 * @returns VBox status code.
1494 * @param pImage The image instance data.
1495 * @param pIoCtx The I/O context.
1496 * @param pClusterAlloc The cluster allocation to rollback.
1497 */
1498static int qcowAsyncClusterAllocRollback(PQCOWIMAGE pImage, PVDIOCTX pIoCtx, PQCOWCLUSTERASYNCALLOC pClusterAlloc)
1499{
[62744]1500 RT_NOREF1(pIoCtx);
[38563]1501 int rc = VINF_SUCCESS;
1502
1503 switch (pClusterAlloc->enmAllocState)
1504 {
1505 case QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC:
1506 case QCOWCLUSTERASYNCALLOCSTATE_L2_LINK:
1507 {
[63741]1508 /* Revert the L1 table entry */
1509 pImage->paL1Table[pClusterAlloc->idxL1] = 0;
[64829]1510 pImage->pL2TblAlloc = NULL;
[63741]1511
1512 /* Assumption right now is that the L1 table is not modified on storage if the link fails. */
[38875]1513 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pClusterAlloc->offNextClusterOld);
[38563]1514 qcowL2TblCacheEntryRelease(pClusterAlloc->pL2Entry); /* Release L2 cache entry. */
[64829]1515 Assert(!pClusterAlloc->pL2Entry->cRefs);
[38563]1516 qcowL2TblCacheEntryFree(pImage, pClusterAlloc->pL2Entry); /* Free it, it is not in the cache yet. */
[56862]1517 break;
[38563]1518 }
1519 case QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC:
1520 case QCOWCLUSTERASYNCALLOCSTATE_USER_LINK:
1521 {
1522 /* Assumption right now is that the L2 table is not modified if the link fails. */
[63741]1523 pClusterAlloc->pL2Entry->paL2Tbl[pClusterAlloc->idxL2] = 0;
[38875]1524 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pClusterAlloc->offNextClusterOld);
[38563]1525 qcowL2TblCacheEntryRelease(pClusterAlloc->pL2Entry); /* Release L2 cache entry. */
[40106]1526 break;
[38563]1527 }
1528 default:
1529 AssertMsgFailed(("Invalid cluster allocation state %d\n", pClusterAlloc->enmAllocState));
1530 rc = VERR_INVALID_STATE;
1531 }
1532
1533 RTMemFree(pClusterAlloc);
1534 return rc;
1535}
1536
1537/**
1538 * Updates the state of the async cluster allocation.
1539 *
1540 * @returns VBox status code.
1541 * @param pBackendData The opaque backend data.
1542 * @param pIoCtx I/O context associated with this request.
1543 * @param pvUser Opaque user data passed during a read/write request.
1544 * @param rcReq Status code for the completed request.
1545 */
1546static DECLCALLBACK(int) qcowAsyncClusterAllocUpdate(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
1547{
1548 int rc = VINF_SUCCESS;
1549 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
1550 PQCOWCLUSTERASYNCALLOC pClusterAlloc = (PQCOWCLUSTERASYNCALLOC)pvUser;
1551
1552 if (RT_FAILURE(rcReq))
1553 return qcowAsyncClusterAllocRollback(pImage, pIoCtx, pClusterAlloc);
1554
1555 AssertPtr(pClusterAlloc->pL2Entry);
1556
1557 switch (pClusterAlloc->enmAllocState)
1558 {
1559 case QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC:
1560 {
[63741]1561 /* Update the link in the in memory L1 table now. */
1562 pImage->paL1Table[pClusterAlloc->idxL1] = pClusterAlloc->pL2Entry->offL2Tbl;
[38563]1563
1564 /* Update the link in the on disk L1 table now. */
1565 pClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_L2_LINK;
[63741]1566 rc = qcowTblWrite(pImage, pIoCtx, pImage->offL1Table, pImage->paL1Table,
1567 pImage->cbL1Table, pImage->cL1TableEntries,
1568 qcowAsyncClusterAllocUpdate, pClusterAlloc);
[38563]1569 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
1570 break;
1571 else if (RT_FAILURE(rc))
1572 {
1573 /* Rollback. */
1574 qcowAsyncClusterAllocRollback(pImage, pIoCtx, pClusterAlloc);
1575 break;
1576 }
1577 /* Success, fall through. */
1578 }
[69046]1579 RT_FALL_THRU();
[38563]1580 case QCOWCLUSTERASYNCALLOCSTATE_L2_LINK:
1581 {
1582 /* L2 link updated in L1 , save L2 entry in cache and allocate new user data cluster. */
1583 uint64_t offData = qcowClusterAllocate(pImage, 1);
1584
[64829]1585 pImage->pL2TblAlloc = NULL;
[38563]1586 qcowL2TblCacheEntryInsert(pImage, pClusterAlloc->pL2Entry);
1587
[38875]1588 pClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC;
1589 pClusterAlloc->offNextClusterOld = offData;
1590 pClusterAlloc->offClusterNew = offData;
[38563]1591
1592 /* Write data. */
[44233]1593 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
1594 offData, pIoCtx, pClusterAlloc->cbToWrite,
1595 qcowAsyncClusterAllocUpdate, pClusterAlloc);
[38563]1596 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
1597 break;
1598 else if (RT_FAILURE(rc))
1599 {
1600 qcowAsyncClusterAllocRollback(pImage, pIoCtx, pClusterAlloc);
1601 RTMemFree(pClusterAlloc);
1602 break;
1603 }
1604 }
[69046]1605 RT_FALL_THRU();
[38563]1606 case QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC:
1607 {
1608 pClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_USER_LINK;
[63741]1609 pClusterAlloc->pL2Entry->paL2Tbl[pClusterAlloc->idxL2] = pClusterAlloc->offClusterNew;
[38563]1610
1611 /* Link L2 table and update it. */
[63741]1612 rc = qcowTblWrite(pImage, pIoCtx, pImage->paL1Table[pClusterAlloc->idxL1],
1613 pClusterAlloc->pL2Entry->paL2Tbl,
1614 pImage->cbL2Table, pImage->cL2TableEntries,
1615 qcowAsyncClusterAllocUpdate, pClusterAlloc);
[38563]1616 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
1617 break;
1618 else if (RT_FAILURE(rc))
1619 {
1620 qcowAsyncClusterAllocRollback(pImage, pIoCtx, pClusterAlloc);
1621 RTMemFree(pClusterAlloc);
1622 break;
1623 }
1624 }
[69046]1625 RT_FALL_THRU();
[38563]1626 case QCOWCLUSTERASYNCALLOCSTATE_USER_LINK:
1627 {
1628 /* Everything done without errors, signal completion. */
1629 qcowL2TblCacheEntryRelease(pClusterAlloc->pL2Entry);
1630 RTMemFree(pClusterAlloc);
1631 rc = VINF_SUCCESS;
1632 break;
1633 }
1634 default:
1635 AssertMsgFailed(("Invalid async cluster allocation state %d\n",
1636 pClusterAlloc->enmAllocState));
1637 }
1638
1639 return rc;
1640}
1641
[82595]1642/**
1643 * Reads a compressed cluster, inflates it and copies the amount of data requested
1644 * into the given I/O context.
1645 *
1646 * @returns VBox status code.
1647 * @param pImage The image instance data.
1648 * @param pIoCtx The I/O context.
1649 * @param offCluster Where to start reading in the uncompressed cluster.
1650 * @param cbToRead How much to read in the uncomrpessed cluster.
1651 * @param offFile Offset where the compressed cluster is stored in the image.
1652 * @param cbCompressedCluster Size of the comrpessed cluster in bytes.
1653 */
1654static int qcowReadCompressedCluster(PQCOWIMAGE pImage, PVDIOCTX pIoCtx,
1655 uint32_t offCluster, size_t cbToRead,
1656 uint64_t offFile, size_t cbCompressedCluster)
1657{
1658 int rc = VINF_SUCCESS;
1659
1660 AssertReturn(!(pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO), VERR_NOT_SUPPORTED); /* Only synchronous I/O supported so far. */
1661
1662 if (cbCompressedCluster > pImage->cbCompCluster)
1663 {
1664 void *pvCompClusterNew = RTMemRealloc(pImage->pvCompCluster, cbCompressedCluster);
1665 if (RT_LIKELY(pvCompClusterNew))
1666 {
1667 pImage->pvCompCluster = pvCompClusterNew;
1668 pImage->cbCompCluster = cbCompressedCluster;
1669 }
1670 else
1671 rc = VERR_NO_MEMORY;
1672 }
1673
1674 if (RT_SUCCESS(rc))
1675 {
1676 rc = vdIfIoIntFileReadMeta(pImage->pIfIo, pImage->pStorage,
1677 offFile, pImage->pvCompCluster,
1678 cbCompressedCluster, NULL,
1679 NULL, NULL, NULL);
1680 if (RT_SUCCESS(rc))
1681 {
1682 if (!pImage->pvCluster)
1683 {
1684 pImage->pvCluster = RTMemAllocZ(pImage->cbCluster);
1685 if (!pImage->pvCluster)
1686 rc = VERR_NO_MEMORY;
1687 }
1688
1689 if (RT_SUCCESS(rc))
1690 {
1691 size_t cbDecomp = 0;
1692
1693 rc = RTZipBlockDecompress(RTZIPTYPE_ZLIB_NO_HEADER, 0 /*fFlags*/,
1694 pImage->pvCompCluster, cbCompressedCluster, NULL,
1695 pImage->pvCluster, pImage->cbCluster, &cbDecomp);
1696 if (RT_SUCCESS(rc))
1697 {
1698 Assert(cbDecomp == pImage->cbCluster);
1699 vdIfIoIntIoCtxCopyTo(pImage->pIfIo, pIoCtx,
1700 (uint8_t *)pImage->pvCluster + offCluster,
1701 cbToRead);
1702 }
1703 }
1704 }
1705 }
1706
1707 return rc;
1708}
1709
[63802]1710/** @copydoc VDIMAGEBACKEND::pfnProbe */
1711static DECLCALLBACK(int) qcowProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
[79965]1712 PVDINTERFACE pVDIfsImage, VDTYPE enmDesiredType, VDTYPE *penmType)
[38563]1713{
[79965]1714 RT_NOREF(pVDIfsDisk, enmDesiredType);
[38563]1715 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
1716 PVDIOSTORAGE pStorage = NULL;
1717 uint64_t cbFile;
1718 int rc = VINF_SUCCESS;
1719
1720 /* Get I/O interface. */
1721 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
1722 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
[90802]1723 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1724 AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
[38563]1725
1726 /*
1727 * Open the file and read the footer.
1728 */
1729 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
1730 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
1731 false /* fCreate */),
1732 &pStorage);
1733 if (RT_SUCCESS(rc))
[62744]1734 {
[38563]1735 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
1736 if ( RT_SUCCESS(rc)
[62744]1737 && cbFile > sizeof(QCowHeader))
[38563]1738 {
[62744]1739 QCowHeader Header;
1740
1741 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &Header, sizeof(Header));
1742 if ( RT_SUCCESS(rc)
1743 && qcowHdrConvertToHostEndianess(&Header))
1744 *penmType = VDTYPE_HDD;
1745 else
1746 rc = VERR_VD_GEN_INVALID_HEADER;
[38563]1747 }
1748 else
1749 rc = VERR_VD_GEN_INVALID_HEADER;
1750 }
1751
1752 if (pStorage)
1753 vdIfIoIntFileClose(pIfIo, pStorage);
1754
1755 LogFlowFunc(("returns %Rrc\n", rc));
1756 return rc;
1757}
1758
[63785]1759/** @copydoc VDIMAGEBACKEND::pfnOpen */
[57388]1760static DECLCALLBACK(int) qcowOpen(const char *pszFilename, unsigned uOpenFlags,
1761 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1762 VDTYPE enmType, void **ppBackendData)
[38563]1763{
[63793]1764 RT_NOREF1(enmType); /**< @todo r=klaus make use of the type info. */
1765
1766 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
1767 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
[38563]1768 int rc;
1769
1770 /* Check open flags. All valid flags are supported. */
[63793]1771 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
[90802]1772 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1773 AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
[38563]1774
[90802]1775
[66486]1776 PQCOWIMAGE pImage = (PQCOWIMAGE)RTMemAllocZ(RT_UOFFSETOF(QCOWIMAGE, RegionList.aRegions[1]));
[63793]1777 if (RT_LIKELY(pImage))
[38563]1778 {
[63793]1779 pImage->pszFilename = pszFilename;
1780 pImage->pStorage = NULL;
1781 pImage->pVDIfsDisk = pVDIfsDisk;
1782 pImage->pVDIfsImage = pVDIfsImage;
[38563]1783
[63793]1784 rc = qcowOpenImage(pImage, uOpenFlags);
1785 if (RT_SUCCESS(rc))
1786 *ppBackendData = pImage;
1787 else
1788 RTMemFree(pImage);
[38563]1789 }
1790 else
[63793]1791 rc = VERR_NO_MEMORY;
[38563]1792
1793 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1794 return rc;
1795}
1796
[63785]1797/** @copydoc VDIMAGEBACKEND::pfnCreate */
[57388]1798static DECLCALLBACK(int) qcowCreate(const char *pszFilename, uint64_t cbSize,
1799 unsigned uImageFlags, const char *pszComment,
1800 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
1801 PCRTUUID pUuid, unsigned uOpenFlags,
1802 unsigned uPercentStart, unsigned uPercentSpan,
1803 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1804 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
1805 void **ppBackendData)
[38563]1806{
[62744]1807 RT_NOREF1(pUuid);
[70848]1808 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p enmType=%u ppBackendData=%#p\n",
[54430]1809 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
[38563]1810 int rc;
1811
[54430]1812 /* Check the VD container type. */
1813 if (enmType != VDTYPE_HDD)
[63793]1814 return VERR_VD_INVALID_TYPE;
[54430]1815
[38563]1816 /* Check open flags. All valid flags are supported. */
[63793]1817 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
[90802]1818 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1819 AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
1820 AssertPtrReturn(pPCHSGeometry, VERR_INVALID_POINTER);
1821 AssertPtrReturn(pLCHSGeometry, VERR_INVALID_POINTER);
[38563]1822
[66486]1823 PQCOWIMAGE pImage = (PQCOWIMAGE)RTMemAllocZ(RT_UOFFSETOF(QCOWIMAGE, RegionList.aRegions[1]));
[63793]1824 if (RT_LIKELY(pImage))
[38563]1825 {
[63793]1826 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
[38563]1827
[63793]1828 pImage->pszFilename = pszFilename;
1829 pImage->pStorage = NULL;
1830 pImage->pVDIfsDisk = pVDIfsDisk;
1831 pImage->pVDIfsImage = pVDIfsImage;
[38563]1832
[63793]1833 rc = qcowCreateImage(pImage, cbSize, uImageFlags, pszComment,
1834 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
1835 pIfProgress, uPercentStart, uPercentSpan);
1836 if (RT_SUCCESS(rc))
[38563]1837 {
[63793]1838 /* So far the image is opened in read/write mode. Make sure the
1839 * image is opened in read-only mode if the caller requested that. */
1840 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
[38563]1841 {
[63793]1842 qcowFreeImage(pImage, false);
1843 rc = qcowOpenImage(pImage, uOpenFlags);
[38563]1844 }
[63793]1845
1846 if (RT_SUCCESS(rc))
1847 *ppBackendData = pImage;
[38563]1848 }
[63793]1849
1850 if (RT_FAILURE(rc))
1851 RTMemFree(pImage);
[38563]1852 }
1853 else
[63793]1854 rc = VERR_NO_MEMORY;
[38563]1855
1856 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1857 return rc;
1858}
1859
[63785]1860/** @copydoc VDIMAGEBACKEND::pfnRename */
[57388]1861static DECLCALLBACK(int) qcowRename(void *pBackendData, const char *pszFilename)
[38563]1862{
1863 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
1864 int rc = VINF_SUCCESS;
1865 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
1866
1867 /* Check arguments. */
[63793]1868 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
[38563]1869
1870 /* Close the image. */
1871 rc = qcowFreeImage(pImage, false);
[63793]1872 if (RT_SUCCESS(rc))
[38563]1873 {
[63793]1874 /* Rename the file. */
1875 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
1876 if (RT_SUCCESS(rc))
1877 {
1878 /* Update pImage with the new information. */
1879 pImage->pszFilename = pszFilename;
[38563]1880
[63793]1881 /* Open the old image with new name. */
1882 rc = qcowOpenImage(pImage, pImage->uOpenFlags);
1883 }
1884 else
1885 {
1886 /* The move failed, try to reopen the original image. */
1887 int rc2 = qcowOpenImage(pImage, pImage->uOpenFlags);
1888 if (RT_FAILURE(rc2))
1889 rc = rc2;
1890 }
[38563]1891 }
1892
1893 LogFlowFunc(("returns %Rrc\n", rc));
1894 return rc;
1895}
1896
[63785]1897/** @copydoc VDIMAGEBACKEND::pfnClose */
[57388]1898static DECLCALLBACK(int) qcowClose(void *pBackendData, bool fDelete)
[38563]1899{
1900 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
1901 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
1902
[63793]1903 int rc = qcowFreeImage(pImage, fDelete);
[38563]1904 RTMemFree(pImage);
1905
1906 LogFlowFunc(("returns %Rrc\n", rc));
1907 return rc;
1908}
1909
[57388]1910static DECLCALLBACK(int) qcowRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
[82595]1911 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
[38563]1912{
[44252]1913 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
1914 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
[38563]1915 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
1916 uint32_t offCluster = 0;
1917 uint32_t idxL1 = 0;
1918 uint32_t idxL2 = 0;
1919 uint64_t offFile = 0;
1920 int rc;
1921
1922 AssertPtr(pImage);
1923 Assert(uOffset % 512 == 0);
1924 Assert(cbToRead % 512 == 0);
[90802]1925 AssertPtrReturn(pIoCtx, VERR_INVALID_POINTER);
1926 AssertReturn(cbToRead, VERR_INVALID_PARAMETER);
[63793]1927 AssertReturn(uOffset + cbToRead <= pImage->cbSize, VERR_INVALID_PARAMETER);
[38563]1928
1929 qcowConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
1930
1931 /* Clip read size to remain in the cluster. */
1932 cbToRead = RT_MIN(cbToRead, pImage->cbCluster - offCluster);
1933
1934 /* Get offset in image. */
[82595]1935 bool fCompressedCluster = false;
1936 size_t cbCompressedCluster = 0;
1937 rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster,
1938 &offFile, &fCompressedCluster, &cbCompressedCluster);
[38563]1939 if (RT_SUCCESS(rc))
[82595]1940 {
1941 if (!fCompressedCluster)
1942 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, offFile,
1943 pIoCtx, cbToRead);
1944 else
1945 rc = qcowReadCompressedCluster(pImage, pIoCtx, offCluster, cbToRead, offFile, cbCompressedCluster);
1946 }
[38563]1947
[44252]1948 if ( ( RT_SUCCESS(rc)
1949 || rc == VERR_VD_BLOCK_FREE
1950 || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
[38563]1951 && pcbActuallyRead)
1952 *pcbActuallyRead = cbToRead;
1953
1954 LogFlowFunc(("returns %Rrc\n", rc));
1955 return rc;
1956}
1957
[57388]1958static DECLCALLBACK(int) qcowWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
[82595]1959 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
1960 size_t *pcbPostRead, unsigned fWrite)
[38563]1961{
[44252]1962 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
1963 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
[38563]1964 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
1965 uint32_t offCluster = 0;
1966 uint32_t idxL1 = 0;
1967 uint32_t idxL2 = 0;
1968 uint64_t offImage = 0;
[44252]1969 int rc = VINF_SUCCESS;
[38563]1970
1971 AssertPtr(pImage);
[44252]1972 Assert(!(uOffset % 512));
1973 Assert(!(cbToWrite % 512));
[90802]1974 AssertPtrReturn(pIoCtx, VERR_INVALID_POINTER);
1975 AssertReturn(cbToWrite, VERR_INVALID_PARAMETER);
[63793]1976 AssertReturn(uOffset + cbToWrite <= pImage->cbSize, VERR_INVALID_PARAMETER);
[38563]1977
[63793]1978 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
[38563]1979 {
[63793]1980 /* Convert offset to L1, L2 index and cluster offset. */
1981 qcowConvertLogicalOffset(pImage, uOffset, &idxL1, &idxL2, &offCluster);
[38563]1982
[63793]1983 /* Clip write size to remain in the cluster. */
1984 cbToWrite = RT_MIN(cbToWrite, pImage->cbCluster - offCluster);
1985 Assert(!(cbToWrite % 512));
[44252]1986
[63793]1987 /* Get offset in image. */
[82595]1988 bool fCompressedCluster = false;
1989 size_t cbCompressedCluster = 0;
1990 rc = qcowConvertToImageOffset(pImage, pIoCtx, idxL1, idxL2, offCluster,
1991 &offImage, &fCompressedCluster, &cbCompressedCluster);
[63793]1992 if (RT_SUCCESS(rc))
[82595]1993 {
1994 if (!fCompressedCluster)
1995 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
1996 offImage, pIoCtx, cbToWrite, NULL, NULL);
1997 else
1998 rc = VERR_NOT_SUPPORTED; /** @todo Support writing compressed clusters */
1999 }
[63793]2000 else if (rc == VERR_VD_BLOCK_FREE)
[38563]2001 {
[63793]2002 if ( cbToWrite == pImage->cbCluster
2003 && !(fWrite & VD_WRITE_NO_ALLOC))
[38563]2004 {
[63793]2005 PQCOWL2CACHEENTRY pL2Entry = NULL;
[38563]2006
[63793]2007 /* Full cluster write to previously unallocated cluster.
2008 * Allocate cluster and write data. */
2009 Assert(!offCluster);
[44252]2010
[63793]2011 do
[38563]2012 {
[63793]2013 /* Check if we have to allocate a new cluster for L2 tables. */
2014 if (!pImage->paL1Table[idxL1])
[44252]2015 {
[63793]2016 uint64_t offL2Tbl;
2017 PQCOWCLUSTERASYNCALLOC pL2ClusterAlloc = NULL;
[38563]2018
[44252]2019 /* Allocate new async cluster allocation state. */
[63793]2020 pL2ClusterAlloc = (PQCOWCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QCOWCLUSTERASYNCALLOC));
2021 if (RT_UNLIKELY(!pL2ClusterAlloc))
[44252]2022 {
2023 rc = VERR_NO_MEMORY;
2024 break;
2025 }
[38563]2026
[63793]2027 pL2Entry = qcowL2TblCacheEntryAlloc(pImage);
2028 if (!pL2Entry)
2029 {
2030 rc = VERR_NO_MEMORY;
2031 RTMemFree(pL2ClusterAlloc);
2032 break;
2033 }
[44252]2034
[63793]2035 offL2Tbl = qcowClusterAllocate(pImage, qcowByte2Cluster(pImage, pImage->cbL2Table));
2036 pL2Entry->offL2Tbl = offL2Tbl;
2037 memset(pL2Entry->paL2Tbl, 0, pImage->cbL2Table);
[44252]2038
[63793]2039 pL2ClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_L2_ALLOC;
2040 pL2ClusterAlloc->offNextClusterOld = offL2Tbl;
2041 pL2ClusterAlloc->offClusterNew = offL2Tbl;
2042 pL2ClusterAlloc->idxL1 = idxL1;
2043 pL2ClusterAlloc->idxL2 = idxL2;
2044 pL2ClusterAlloc->cbToWrite = cbToWrite;
2045 pL2ClusterAlloc->pL2Entry = pL2Entry;
2046
[64829]2047 pImage->pL2TblAlloc = pL2Entry;
2048
2049 LogFlowFunc(("Allocating new L2 table at cluster offset %llu\n", offL2Tbl));
2050
[63793]2051 /*
2052 * Write the L2 table first and link to the L1 table afterwards.
2053 * If something unexpected happens the worst case which can happen
2054 * is a leak of some clusters.
2055 */
2056 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
2057 offL2Tbl, pL2Entry->paL2Tbl, pImage->cbL2Table, pIoCtx,
2058 qcowAsyncClusterAllocUpdate, pL2ClusterAlloc);
[44252]2059 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
2060 break;
2061 else if (RT_FAILURE(rc))
2062 {
[63793]2063 RTMemFree(pL2ClusterAlloc);
2064 qcowL2TblCacheEntryFree(pImage, pL2Entry);
[44252]2065 break;
2066 }
2067
[63793]2068 rc = qcowAsyncClusterAllocUpdate(pImage, pIoCtx, pL2ClusterAlloc, rc);
[44252]2069 }
[63793]2070 else
2071 {
[64829]2072 LogFlowFunc(("Fetching L2 table at cluster offset %llu\n", pImage->paL1Table[idxL1]));
2073
[63793]2074 rc = qcowL2TblCacheFetch(pImage, pIoCtx, pImage->paL1Table[idxL1],
2075 &pL2Entry);
2076 if (RT_SUCCESS(rc))
2077 {
2078 PQCOWCLUSTERASYNCALLOC pDataClusterAlloc = NULL;
[38563]2079
[63793]2080 /* Allocate new async cluster allocation state. */
2081 pDataClusterAlloc = (PQCOWCLUSTERASYNCALLOC)RTMemAllocZ(sizeof(QCOWCLUSTERASYNCALLOC));
2082 if (RT_UNLIKELY(!pDataClusterAlloc))
2083 {
2084 rc = VERR_NO_MEMORY;
2085 break;
2086 }
[38563]2087
[63793]2088 /* Allocate new cluster for the data. */
2089 uint64_t offData = qcowClusterAllocate(pImage, 1);
2090
2091 pDataClusterAlloc->enmAllocState = QCOWCLUSTERASYNCALLOCSTATE_USER_ALLOC;
2092 pDataClusterAlloc->offNextClusterOld = offData;
2093 pDataClusterAlloc->offClusterNew = offData;
2094 pDataClusterAlloc->idxL1 = idxL1;
2095 pDataClusterAlloc->idxL2 = idxL2;
2096 pDataClusterAlloc->cbToWrite = cbToWrite;
2097 pDataClusterAlloc->pL2Entry = pL2Entry;
2098
2099 /* Write data. */
2100 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
2101 offData, pIoCtx, cbToWrite,
2102 qcowAsyncClusterAllocUpdate, pDataClusterAlloc);
2103 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
2104 break;
2105 else if (RT_FAILURE(rc))
2106 {
2107 RTMemFree(pDataClusterAlloc);
2108 break;
2109 }
2110
2111 rc = qcowAsyncClusterAllocUpdate(pImage, pIoCtx, pDataClusterAlloc, rc);
2112 }
2113 }
2114
2115 } while (0);
2116
2117 *pcbPreRead = 0;
2118 *pcbPostRead = 0;
2119 }
2120 else
2121 {
2122 /* Trying to do a partial write to an unallocated cluster. Don't do
2123 * anything except letting the upper layer know what to do. */
2124 *pcbPreRead = offCluster;
2125 *pcbPostRead = pImage->cbCluster - cbToWrite - *pcbPreRead;
2126 }
[38563]2127 }
[63793]2128
2129 if (pcbWriteProcess)
2130 *pcbWriteProcess = cbToWrite;
[38563]2131 }
[63793]2132 else
2133 rc = VERR_VD_IMAGE_READ_ONLY;
[38563]2134
2135 LogFlowFunc(("returns %Rrc\n", rc));
2136 return rc;
2137}
2138
[57388]2139static DECLCALLBACK(int) qcowFlush(void *pBackendData, PVDIOCTX pIoCtx)
[38563]2140{
2141 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
2142 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
[44252]2143 int rc = VINF_SUCCESS;
[38563]2144
[63793]2145 AssertPtr(pImage);
2146 AssertPtrReturn(pIoCtx, VERR_INVALID_PARAMETER);
[44252]2147
[63793]2148 if ( pImage->pStorage
2149 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2150 {
2151 QCowHeader Header;
[44252]2152
[63793]2153 rc = qcowTblWrite(pImage, pIoCtx, pImage->offL1Table, pImage->paL1Table,
2154 pImage->cbL1Table, pImage->cL1TableEntries, NULL, NULL);
2155 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
2156 {
2157 /* Write header. */
2158 size_t cbHeader = 0;
2159 qcowHdrConvertFromHostEndianess(pImage, &Header, &cbHeader);
2160 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
2161 0, &Header, cbHeader,
2162 pIoCtx, NULL, NULL);
2163 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
2164 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage,
2165 pIoCtx, NULL, NULL);
2166 }
2167 }
2168
[38563]2169 LogFlowFunc(("returns %Rrc\n", rc));
2170 return rc;
2171}
2172
[63785]2173/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
[57388]2174static DECLCALLBACK(unsigned) qcowGetVersion(void *pBackendData)
[38563]2175{
2176 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
2177 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
2178
[63793]2179 AssertPtrReturn(pImage, 0);
[38563]2180
[63793]2181 return pImage->uVersion;
[38563]2182}
2183
[63785]2184/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
[57388]2185static DECLCALLBACK(uint64_t) qcowGetFileSize(void *pBackendData)
[38563]2186{
2187 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
2188 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
2189 uint64_t cb = 0;
2190
[63793]2191 AssertPtrReturn(pImage, 0);
[38563]2192
[63793]2193 uint64_t cbFile;
2194 if (pImage->pStorage)
[38563]2195 {
[63793]2196 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
2197 if (RT_SUCCESS(rc))
2198 cb += cbFile;
[38563]2199 }
2200
2201 LogFlowFunc(("returns %lld\n", cb));
2202 return cb;
2203}
2204
[63785]2205/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
[63793]2206static DECLCALLBACK(int) qcowGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
[38563]2207{
2208 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
2209 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
[63793]2210 int rc = VINF_SUCCESS;
[38563]2211
[63793]2212 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[38563]2213
[63793]2214 if (pImage->PCHSGeometry.cCylinders)
2215 *pPCHSGeometry = pImage->PCHSGeometry;
[38563]2216 else
[63793]2217 rc = VERR_VD_GEOMETRY_NOT_SET;
[38563]2218
2219 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
2220 return rc;
2221}
2222
[63785]2223/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
[63793]2224static DECLCALLBACK(int) qcowSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
[38563]2225{
[63793]2226 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n",
2227 pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
[38563]2228 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
[63793]2229 int rc = VINF_SUCCESS;
[38563]2230
[63793]2231 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[38563]2232
[63793]2233 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2234 rc = VERR_VD_IMAGE_READ_ONLY;
2235 else
[38563]2236 pImage->PCHSGeometry = *pPCHSGeometry;
2237
2238 LogFlowFunc(("returns %Rrc\n", rc));
2239 return rc;
2240}
2241
[63785]2242/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
[63793]2243static DECLCALLBACK(int) qcowGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
[38563]2244{
[63793]2245 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
[38563]2246 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
[63793]2247 int rc = VINF_SUCCESS;
[38563]2248
[63793]2249 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[38563]2250
[63793]2251 if (pImage->LCHSGeometry.cCylinders)
2252 *pLCHSGeometry = pImage->LCHSGeometry;
[38563]2253 else
[63793]2254 rc = VERR_VD_GEOMETRY_NOT_SET;
[38563]2255
[63793]2256 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders,
2257 pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
[38563]2258 return rc;
2259}
2260
[63785]2261/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
[63793]2262static DECLCALLBACK(int) qcowSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
[38563]2263{
[63793]2264 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData,
2265 pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
[38563]2266 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
[63793]2267 int rc = VINF_SUCCESS;
[38563]2268
[63793]2269 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[38563]2270
[63793]2271 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2272 rc = VERR_VD_IMAGE_READ_ONLY;
2273 else
[38563]2274 pImage->LCHSGeometry = *pLCHSGeometry;
2275
2276 LogFlowFunc(("returns %Rrc\n", rc));
2277 return rc;
2278}
2279
[66486]2280/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
2281static DECLCALLBACK(int) qcowQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
2282{
2283 LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
2284 PQCOWIMAGE pThis = (PQCOWIMAGE)pBackendData;
2285
2286 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
2287
2288 *ppRegionList = &pThis->RegionList;
2289 LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
2290 return VINF_SUCCESS;
2291}
2292
2293/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
2294static DECLCALLBACK(void) qcowRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
2295{
2296 RT_NOREF1(pRegionList);
2297 LogFlowFunc(("pBackendData=%#p pRegionList=%#p\n", pBackendData, pRegionList));
2298 PQCOWIMAGE pThis = (PQCOWIMAGE)pBackendData;
2299 AssertPtr(pThis); RT_NOREF(pThis);
2300
2301 /* Nothing to do here. */
2302}
2303
[63785]2304/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
[57388]2305static DECLCALLBACK(unsigned) qcowGetImageFlags(void *pBackendData)
[38563]2306{
2307 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
2308 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
2309
[63793]2310 AssertPtrReturn(pImage, 0);
[38563]2311
[63793]2312 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
2313 return pImage->uImageFlags;
[38563]2314}
2315
[63785]2316/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
[57388]2317static DECLCALLBACK(unsigned) qcowGetOpenFlags(void *pBackendData)
[38563]2318{
2319 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
2320 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
2321
[63793]2322 AssertPtrReturn(pImage, 0);
[38563]2323
[63793]2324 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
2325 return pImage->uOpenFlags;
[38563]2326}
2327
[63785]2328/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
[57388]2329static DECLCALLBACK(int) qcowSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
[38563]2330{
2331 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
2332 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
[63793]2333 int rc = VINF_SUCCESS;
[38563]2334
2335 /* Image must be opened and the new flags must be valid. */
[44232]2336 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
[63793]2337 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
2338 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
2339 rc = VERR_INVALID_PARAMETER;
2340 else
[38563]2341 {
[63793]2342 /* Implement this operation via reopening the image. */
2343 rc = qcowFreeImage(pImage, false);
2344 if (RT_SUCCESS(rc))
2345 rc = qcowOpenImage(pImage, uOpenFlags);
[38563]2346 }
2347
2348 LogFlowFunc(("returns %Rrc\n", rc));
2349 return rc;
2350}
2351
[63785]2352/** @copydoc VDIMAGEBACKEND::pfnGetComment */
[66494]2353VD_BACKEND_CALLBACK_GET_COMMENT_DEF_NOT_SUPPORTED(qcowGetComment);
[38563]2354
[63785]2355/** @copydoc VDIMAGEBACKEND::pfnSetComment */
[66494]2356VD_BACKEND_CALLBACK_SET_COMMENT_DEF_NOT_SUPPORTED(qcowSetComment, PQCOWIMAGE);
[38563]2357
[63785]2358/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
[66494]2359VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(qcowGetUuid);
[38563]2360
[63785]2361/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
[66494]2362VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(qcowSetUuid, PQCOWIMAGE);
[38563]2363
[63785]2364/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
[66494]2365VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(qcowGetModificationUuid);
[38563]2366
[63785]2367/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
[66494]2368VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(qcowSetModificationUuid, PQCOWIMAGE);
[38563]2369
[63785]2370/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
[66494]2371VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(qcowGetParentUuid);
[38563]2372
[63785]2373/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
[66494]2374VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(qcowSetParentUuid, PQCOWIMAGE);
[38563]2375
[63785]2376/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
[66494]2377VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(qcowGetParentModificationUuid);
[38563]2378
[63785]2379/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
[66494]2380VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(qcowSetParentModificationUuid, PQCOWIMAGE);
[38563]2381
[63785]2382/** @copydoc VDIMAGEBACKEND::pfnDump */
[57388]2383static DECLCALLBACK(void) qcowDump(void *pBackendData)
[38563]2384{
2385 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
2386
[63793]2387 AssertPtrReturnVoid(pImage);
2388 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
2389 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
2390 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
2391 pImage->cbSize / 512);
[38563]2392}
2393
[63785]2394/** @copydoc VDIMAGEBACKEND::pfnGetParentFilename */
[57388]2395static DECLCALLBACK(int) qcowGetParentFilename(void *pBackendData, char **ppszParentFilename)
[38563]2396{
2397 int rc = VINF_SUCCESS;
2398 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
2399
2400 AssertPtr(pImage);
2401 if (pImage)
[44940]2402 if (pImage->pszBackingFilename)
[38563]2403 *ppszParentFilename = RTStrDup(pImage->pszBackingFilename);
2404 else
2405 rc = VERR_NOT_SUPPORTED;
2406 else
2407 rc = VERR_VD_NOT_OPENED;
2408
2409 LogFlowFunc(("returns %Rrc\n", rc));
2410 return rc;
2411}
2412
[63785]2413/** @copydoc VDIMAGEBACKEND::pfnSetParentFilename */
[57388]2414static DECLCALLBACK(int) qcowSetParentFilename(void *pBackendData, const char *pszParentFilename)
[38563]2415{
2416 int rc = VINF_SUCCESS;
2417 PQCOWIMAGE pImage = (PQCOWIMAGE)pBackendData;
2418
2419 AssertPtr(pImage);
2420 if (pImage)
2421 {
2422 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2423 rc = VERR_VD_IMAGE_READ_ONLY;
2424 else if ( pImage->pszBackingFilename
2425 && (strlen(pszParentFilename) > pImage->cbBackingFilename))
2426 rc = VERR_NOT_SUPPORTED; /* The new filename is longer than the old one. */
2427 else
2428 {
2429 if (pImage->pszBackingFilename)
2430 RTStrFree(pImage->pszBackingFilename);
2431 pImage->pszBackingFilename = RTStrDup(pszParentFilename);
2432 if (!pImage->pszBackingFilename)
[77232]2433 rc = VERR_NO_STR_MEMORY;
[38563]2434 else
2435 {
2436 if (!pImage->offBackingFilename)
2437 {
2438 /* Allocate new cluster. */
2439 uint64_t offData = qcowClusterAllocate(pImage, 1);
2440
2441 Assert((offData & UINT32_MAX) == offData);
2442 pImage->offBackingFilename = (uint32_t)offData;
[48851]2443 pImage->cbBackingFilename = (uint32_t)strlen(pszParentFilename);
[38563]2444 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage,
2445 offData + pImage->cbCluster);
2446 }
2447
2448 if (RT_SUCCESS(rc))
2449 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
2450 pImage->offBackingFilename,
2451 pImage->pszBackingFilename,
[44233]2452 strlen(pImage->pszBackingFilename));
[38563]2453 }
2454 }
2455 }
2456 else
2457 rc = VERR_VD_NOT_OPENED;
2458
2459 LogFlowFunc(("returns %Rrc\n", rc));
2460 return rc;
2461}
2462
2463
2464
[63781]2465const VDIMAGEBACKEND g_QCowBackend =
[38563]2466{
[63905]2467 /* u32Version */
2468 VD_IMGBACKEND_VERSION,
[38563]2469 /* pszBackendName */
2470 "QCOW",
2471 /* uBackendCaps */
2472 VD_CAP_FILE | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF | VD_CAP_ASYNC,
2473 /* paFileExtensions */
2474 s_aQCowFileExtensions,
2475 /* paConfigInfo */
2476 NULL,
[63802]2477 /* pfnProbe */
2478 qcowProbe,
[38563]2479 /* pfnOpen */
2480 qcowOpen,
2481 /* pfnCreate */
2482 qcowCreate,
2483 /* pfnRename */
2484 qcowRename,
2485 /* pfnClose */
2486 qcowClose,
2487 /* pfnRead */
2488 qcowRead,
2489 /* pfnWrite */
2490 qcowWrite,
2491 /* pfnFlush */
2492 qcowFlush,
[44252]2493 /* pfnDiscard */
2494 NULL,
[38563]2495 /* pfnGetVersion */
2496 qcowGetVersion,
2497 /* pfnGetFileSize */
2498 qcowGetFileSize,
2499 /* pfnGetPCHSGeometry */
2500 qcowGetPCHSGeometry,
2501 /* pfnSetPCHSGeometry */
2502 qcowSetPCHSGeometry,
2503 /* pfnGetLCHSGeometry */
2504 qcowGetLCHSGeometry,
2505 /* pfnSetLCHSGeometry */
2506 qcowSetLCHSGeometry,
[66110]2507 /* pfnQueryRegions */
[66486]2508 qcowQueryRegions,
[66110]2509 /* pfnRegionListRelease */
[66486]2510 qcowRegionListRelease,
[38563]2511 /* pfnGetImageFlags */
2512 qcowGetImageFlags,
2513 /* pfnGetOpenFlags */
2514 qcowGetOpenFlags,
2515 /* pfnSetOpenFlags */
2516 qcowSetOpenFlags,
2517 /* pfnGetComment */
2518 qcowGetComment,
2519 /* pfnSetComment */
2520 qcowSetComment,
2521 /* pfnGetUuid */
2522 qcowGetUuid,
2523 /* pfnSetUuid */
2524 qcowSetUuid,
2525 /* pfnGetModificationUuid */
2526 qcowGetModificationUuid,
2527 /* pfnSetModificationUuid */
2528 qcowSetModificationUuid,
2529 /* pfnGetParentUuid */
2530 qcowGetParentUuid,
2531 /* pfnSetParentUuid */
2532 qcowSetParentUuid,
2533 /* pfnGetParentModificationUuid */
2534 qcowGetParentModificationUuid,
2535 /* pfnSetParentModificationUuid */
2536 qcowSetParentModificationUuid,
2537 /* pfnDump */
2538 qcowDump,
[58132]2539 /* pfnGetTimestamp */
[38563]2540 NULL,
[58132]2541 /* pfnGetParentTimestamp */
[38563]2542 NULL,
[58132]2543 /* pfnSetParentTimestamp */
[38563]2544 NULL,
2545 /* pfnGetParentFilename */
2546 qcowGetParentFilename,
2547 /* pfnSetParentFilename */
2548 qcowSetParentFilename,
2549 /* pfnComposeLocation */
2550 genericFileComposeLocation,
2551 /* pfnComposeName */
2552 genericFileComposeName,
2553 /* pfnCompact */
2554 NULL,
2555 /* pfnResize */
[38621]2556 NULL,
[39519]2557 /* pfnRepair */
[50988]2558 NULL,
2559 /* pfnTraverseMetadata */
[63905]2560 NULL,
2561 /* u32VersionEnd */
2562 VD_IMGBACKEND_VERSION
[38563]2563};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette