VirtualBox

source: vbox/trunk/src/VBox/Storage/VHDX.cpp@ 41350

Last change on this file since 41350 was 41350, checked in by vboxsync, 13 years ago

Storage/VHDX: Fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.4 KB
Line 
1/* $Id: VHDX.cpp 41350 2012-05-18 10:43:04Z vboxsync $ */
2/** @file
3 * VHDX - VHDX Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEFAULT /** @todo: Log group */
22#include <VBox/vd-plugin.h>
23#include <VBox/err.h>
24
25#include <VBox/log.h>
26#include <iprt/assert.h>
27#include <iprt/alloc.h>
28#include <iprt/path.h>
29#include <iprt/uuid.h>
30#include <iprt/crc.h>
31
32/*******************************************************************************
33* On disk data structures *
34*******************************************************************************/
35
36/**
37 * VHDX file type identifier.
38 */
39#pragma pack(1)
40typedef struct VhdxFileIdentifier
41{
42 /** Signature. */
43 uint64_t u64Signature;
44 /** Creator ID - UTF-16 string (not neccessarily null terminated). */
45 uint16_t awszCreator[256];
46} VhdxFileIdentifier;
47#pragma pack()
48/** Pointer to an on disk VHDX file type identifier. */
49typedef VhdxFileIdentifier *PVhdxFileIdentifier;
50
51/** VHDX file type identifier signature ("vhdxfile"). */
52#define VHDX_FILE_IDENTIFIER_SIGNATURE UINT64_C(0x656c696678646876)
53/** Start offset of the VHDX file type identifier. */
54#define VHDX_FILE_IDENTIFIER_OFFSET UINT64_C(0)
55
56/**
57 * VHDX header.
58 */
59#pragma pack(1)
60typedef struct VhdxHeader
61{
62 /** Signature. */
63 uint32_t u32Signature;
64 /** Checksum. */
65 uint32_t u32Checksum;
66 /** Sequence number. */
67 uint64_t u64SequenceNumber;
68 /** File write UUID. */
69 RTUUID UuidFileWrite;
70 /** Data write UUID. */
71 RTUUID UuidDataWrite;
72 /** Log UUID. */
73 RTUUID UuidLog;
74 /** Version of the log format. */
75 uint16_t u16LogVersion;
76 /** VHDX format version.. */
77 uint16_t u16Version;
78 /** Length of the log region. */
79 uint32_t u32LogLength;
80 /** Start offset of the log offset in the file. */
81 uint64_t u64LogOffset;
82 /** Reserved bytes. */
83 uint8_t u8Reserved[4016];
84} VhdxHeader;
85#pragma pack()
86/** Pointer to an on disk VHDX header. */
87typedef VhdxHeader *PVhdxHeader;
88
89/** VHDX header signature ("head"). */
90#define VHDX_HEADER_SIGNATURE UINT32_C(0x64616568)
91/** Start offset of the first VHDX header. */
92#define VHDX_HEADER1_OFFSET _64K
93/** Start offset of the second VHDX header. */
94#define VHDX_HEADER2_OFFSET _128K
95/** Current Log format version. */
96#define VHDX_HEADER_LOG_VERSION UINT16_C(0)
97/** Current VHDX format version. */
98#define VHDX_HEADER_VHDX_VERSION UINT16_C(1)
99
100/**
101 * VHDX region table header
102 */
103#pragma pack(1)
104typedef struct VhdxRegionTblHdr
105{
106 /** Signature. */
107 uint32_t u32Signature;
108 /** Checksum. */
109 uint32_t u32Checksum;
110 /** Number of region table entries following this header. */
111 uint32_t u32EntryCount;
112 /** Reserved. */
113 uint32_t u32Reserved;
114} VhdxRegionTblHdr;
115#pragma pack()
116/** Pointer to an on disk VHDX region table header. */
117typedef VhdxRegionTblHdr *PVhdxRegionTblHdr;
118
119/** VHDX region table header signature. */
120#define VHDX_REGION_TBL_HDR_SIGNATURE UINT32_C(0x69676572)
121/** Maximum number of entries which can follow. */
122#define VHDX_REGION_TBL_HDR_ENTRY_COUNT_MAX UINT32_C(2047)
123/** Offset where the region table is stored (192 KB). */
124#define VHDX_REGION_TBL_HDR_OFFSET UINT64_C(196608)
125/** Maximum size of the region table. */
126#define VHDX_REGION_TBL_SIZE_MAX _64K
127
128/**
129 * VHDX region table entry.
130 */
131#pragma pack(1)
132typedef struct VhdxRegionTblEntry
133{
134 /** Object UUID. */
135 RTUUID UuidObject;
136 /** File offset of the region. */
137 uint64_t u64FileOffset;
138 /** Length of the region in bytes. */
139 uint32_t u32Length;
140 /** Flags for this object. */
141 uint32_t u32Flags;
142} VhdxRegionTblEntry;
143#pragma pack()
144/** Pointer to an on disk VHDX region table entry. */
145typedef struct VhdxRegionTblEntry *PVhdxRegionTblEntry;
146
147/** Flag whether this region is required. */
148#define VHDX_REGION_TBL_ENTRY_FLAGS_IS_REQUIRED RT_BIT_32(0)
149/** UUID for the BAT region. */
150#define VHDX_REGION_TBL_ENTRY_UUID_BAT "2dc27766-f623-4200-9d64-115e9bfd4a08"
151/** UUID for the metadata region. */
152#define VHDX_REGION_TBL_ENTRY_UUID_METADATA "8b7ca206-4790-4b9a-b8fe-575f050f886e"
153
154/**
155 * VHDX Log entry header.
156 */
157#pragma pack(1)
158typedef struct VhdxLogEntryHdr
159{
160 /** Signature. */
161 uint32_t u32Signature;
162 /** Checksum. */
163 uint32_t u32Checksum;
164 /** Total length of the entry in bytes. */
165 uint32_t u32EntryLength;
166 /** Tail of the log entries. */
167 uint32_t u32Tail;
168 /** Sequence number. */
169 uint64_t u64SequenceNumber;
170 /** Number of descriptors in this log entry. */
171 uint32_t u32DescriptorCount;
172 /** Reserved. */
173 uint32_t u32Reserved;
174 /** Log UUID. */
175 RTUUID UuidLog;
176 /** VHDX file size in bytes while the log entry was written. */
177 uint64_t u64FlushedFileOffset;
178 /** File size in bytes all allocated file structures fit into when the
179 * log entry was written. */
180 uint64_t u64LastFileOffset;
181} VhdxLogEntryHdr;
182#pragma pack()
183/** Pointer to an on disk VHDX log entry header. */
184typedef struct VhdxLogEntryHdr *PVhdxLogEntryHdr;
185
186/** VHDX log entry signature ("loge"). */
187#define VHDX_LOG_ENTRY_HEADER_SIGNATURE UINT32_C(0x65676f6c)
188
189/**
190 * VHDX log zero descriptor.
191 */
192#pragma pack(1)
193typedef struct VhdxLogZeroDesc
194{
195 /** Signature of this descriptor. */
196 uint32_t u32ZeroSignature;
197 /** Reserved. */
198 uint32_t u32Reserved;
199 /** Length of the section to zero. */
200 uint64_t u64ZeroLength;
201 /** File offset to write zeros to. */
202 uint64_t u64FileOffset;
203 /** Sequence number (must macht the field in the log entry header). */
204 uint64_t u64SequenceNumber;
205} VhdxLogZeroDesc;
206#pragma pack()
207/** Pointer to an on disk VHDX log zero descriptor. */
208typedef struct VhdxLogZeroDesc *PVhdxLogZeroDesc;
209
210/** Signature of a VHDX log zero descriptor ("zero"). */
211#define VHDX_LOG_ZERO_DESC_SIGNATURE UINT32_C(0x6f72657a)
212
213/**
214 * VHDX log data descriptor.
215 */
216#pragma pack(1)
217typedef struct VhdxLogDataDesc
218{
219 /** Signature of this descriptor. */
220 uint32_t u32DataSignature;
221 /** Trailing 4 bytes removed from the update. */
222 uint32_t u32TrailingBytes;
223 /** Leading 8 bytes removed from the update. */
224 uint64_t u64LeadingBytes;
225 /** File offset to write zeros to. */
226 uint64_t u64FileOffset;
227 /** Sequence number (must macht the field in the log entry header). */
228 uint64_t u64SequenceNumber;
229} VhdxLogDataDesc;
230#pragma pack()
231/** Pointer to an on disk VHDX log data descriptor. */
232typedef struct VhdxLogDataDesc *PVhdxLogDataDesc;
233
234/** Signature of a VHDX log data descriptor ("desc"). */
235#define VHDX_LOG_DATA_DESC_SIGNATURE UINT32_C(0x63736564)
236
237/**
238 * VHDX log data sector.
239 */
240#pragma pack(1)
241typedef struct VhdxLogDataSector
242{
243 /** Signature of the data sector. */
244 uint32_t u32DataSignature;
245 /** 4 most significant bytes of the sequence number. */
246 uint32_t u32SequenceHigh;
247 /** Raw data associated with the update. */
248 uint8_t u8Data[4084];
249 /** 4 least significant bytes of the sequence number. */
250 uint32_t u32SequenceLow;
251} VhdxLogDataSector;
252#pragma pack()
253/** Pointer to an on disk VHDX log data sector. */
254typedef VhdxLogDataSector *PVhdxLogDataSector;
255
256/** Signature of a VHDX log data sector ("data"). */
257#define VHDX_LOG_DATA_SECTOR_SIGNATURE UINT32_C(0x61746164)
258
259/**
260 * VHDX BAT entry.
261 */
262#pragma pack(1)
263typedef struct VhdxBatEntry
264{
265 /** The BAT entry, contains state and offset. */
266 uint64_t u64BatEntry;
267} VhdxBatEntry;
268#pragma pack()
269typedef VhdxBatEntry *PVhdxBatEntry;
270
271/** Return the BAT state from a given entry. */
272#define VHDX_BAT_ENTRY_GET_STATE(bat) ((bat) & UINT64_C(0x7))
273/** Get the FileOffsetMB field from a given BAT entry. */
274#define VHDX_BAT_ENTRY_GET_FILE_OFFSET_MB(bat) (((bat) & UINT64_C(0xfffffffffff00000)) >> 20)
275/** Get a byte offset from the BAT entry. */
276#define VHDX_BAT_ENTRY_GET_FILE_OFFSET(bat) (VHDX_BAT_ENTRY_GET_FILE_OFFSET_MB(bat) * (uint64_t)_1M)
277
278/** Block not present and the data is undefined. */
279#define VHDX_BAT_ENTRY_PAYLOAD_BLOCK_NOT_PRESENT (0)
280/** Data in this block is undefined. */
281#define VHDX_BAT_ENTRY_PAYLOAD_BLOCK_UNDEFINED (1)
282/** Data in this block contains zeros. */
283#define VHDX_BAT_ENTRY_PAYLOAD_BLOCK_ZERO (2)
284/** Block was unmapped by the application or system and data is either zero or
285 * the data before the block was unmapped. */
286#define VHDX_BAT_ENTRY_PAYLOAD_BLOCK_UNMAPPED (3)
287/** Block data is in the file pointed to by the FileOffsetMB field. */
288#define VHDX_BAT_ENTRY_PAYLOAD_BLOCK_FULLY_PRESENT (6)
289/** Block is partially present, use sector bitmap to get present sectors. */
290#define VHDX_BAT_ENTRY_PAYLOAD_BLOCK_PARTIALLY_PRESENT (7)
291
292/** The sector bitmap block is undefined and not allocated in the file. */
293#define VHDX_BAT_ENTRY_SB_BLOCK_NOT_PRESENT (0)
294/** The sector bitmap block is defined at the file location. */
295#define VHDX_BAT_ENTRY_SB_BLOCK_PRESENT (6)
296
297/**
298 * VHDX Metadata tabl header.
299 */
300#pragma pack(1)
301typedef struct VhdxMetadataTblHdr
302{
303 /** Signature. */
304 uint64_t u64Signature;
305 /** Reserved. */
306 uint16_t u16Reserved;
307 /** Number of entries in the table. */
308 uint16_t u16EntryCount;
309 /** Reserved */
310 uint32_t u32Reserved2[5];
311} VhdxMetadataTblHdr;
312#pragma pack()
313/** Pointer to an on disk metadata table header. */
314typedef VhdxMetadataTblHdr *PVhdxMetadataTblHdr;
315
316/** Signature of a VHDX metadata table header ("metadata"). */
317#define VHDX_METADATA_TBL_HDR_SIGNATURE UINT64_C(0x617461646174656d)
318/** Maximum number of entries the metadata table can have. */
319#define VHDX_METADATA_TBL_HDR_ENTRY_COUNT_MAX UINT16_C(2047)
320
321/**
322 * VHDX Metadata table entry.
323 */
324#pragma pack(1)
325typedef struct VhdxMetadataTblEntry
326{
327 /** Item UUID. */
328 RTUUID UuidItem;
329 /** Offset of the metadata item. */
330 uint32_t u32Offset;
331 /** Length of the metadata item. */
332 uint32_t u32Length;
333 /** Flags for the metadata item. */
334 uint32_t u32Flags;
335 /** Reserved. */
336 uint32_t u32Reserved;
337} VhdxMetadataTblEntry;
338#pragma pack()
339/** Pointer to an on disk metadata table entry. */
340typedef VhdxMetadataTblEntry *PVhdxMetadataTblEntry;
341
342/** FLag whether the metadata item is system or user metadata. */
343#define VHDX_METADATA_TBL_ENTRY_FLAGS_IS_USER RT_BIT_32(0)
344/** FLag whether the metadata item is file or virtual disk metadata. */
345#define VHDX_METADATA_TBL_ENTRY_FLAGS_IS_VDISK RT_BIT_32(1)
346/** FLag whether the backend must understand the metadata item to load the image. */
347#define VHDX_METADATA_TBL_ENTRY_FLAGS_IS_REQUIRED RT_BIT_32(2)
348
349/** File parameters item UUID. */
350#define VHDX_METADATA_TBL_ENTRY_ITEM_FILE_PARAMS "caa16737-fa36-4d43-b3b6-33f0aa44e76b"
351/** Virtual disk size item UUID. */
352#define VHDX_METADATA_TBL_ENTRY_ITEM_VDISK_SIZE "2fa54224-cd1b-4876-b211-5dbed83bf4b8"
353/** Page 83 UUID. */
354#define VHDX_METADATA_TBL_ENTRY_ITEM_PAGE83_DATA "beca12ab-b2e6-4523-93ef-c309e000c746"
355/** Logical sector size UUID. */
356#define VHDX_METADATA_TBL_ENTRY_ITEM_LOG_SECT_SIZE "8141bf1d-a96f-4709-ba47-f233a8faab5f"
357/** Physical sector size UUID. */
358#define VHDX_METADATA_TBL_ENTRY_ITEM_PHYS_SECT_SIZE "cda348c7-445d-4471-9cc9-e9885251c556"
359/** Parent locator UUID. */
360#define VHDX_METADATA_TBL_ENTRY_ITEM_PARENT_LOCATOR "a8d35f2d-b30b-454d-abf7-d3d84834ab0c"
361
362/**
363 * VHDX File parameters metadata item.
364 */
365#pragma pack(1)
366typedef struct VhdxFileParameters
367{
368 /** Block size. */
369 uint32_t u32BlockSize;
370 /** Flags. */
371 uint32_t u32Flags;
372} VhdxFileParameters;
373#pragma pack()
374/** Pointer to an on disk VHDX file parameters metadata item. */
375typedef struct VhdxFileParameters *PVhdxFileParameters;
376
377/** Flag whether to leave blocks allocated in the file or if it is possible to unmap them. */
378#define VHDX_FILE_PARAMETERS_FLAGS_LEAVE_BLOCKS_ALLOCATED RT_BIT_32(0)
379/** Flag whether this file has a parent VHDX file. */
380#define VHDX_FILE_PARAMETERS_FLAGS_HAS_PARENT RT_BIT_32(1)
381
382/**
383 * VHDX virtual disk size metadata item.
384 */
385#pragma pack(1)
386typedef struct VhdxVDiskSize
387{
388 /** Virtual disk size. */
389 uint64_t u64VDiskSize;
390} VhdxVDiskSize;
391#pragma pack()
392/** Pointer to an on disk VHDX virtual disk size metadata item. */
393typedef struct VhdxVDiskSize *PVhdxVDiskSize;
394
395/**
396 * VHDX page 83 data metadata item.
397 */
398#pragma pack(1)
399typedef struct VhdxPage83Data
400{
401 /** UUID for the SCSI device. */
402 RTUUID UuidPage83Data;
403} VhdxPage83Data;
404#pragma pack()
405/** Pointer to an on disk VHDX vpage 83 data metadata item. */
406typedef struct VhdxPage83Data *PVhdxPage83Data;
407
408/**
409 * VHDX virtual disk logical sector size.
410 */
411#pragma pack(1)
412typedef struct VhdxVDiskLogicalSectorSize
413{
414 /** Logical sector size. */
415 uint32_t u32LogicalSectorSize;
416} VhdxVDiskLogicalSectorSize;
417#pragma pack()
418/** Pointer to an on disk VHDX virtual disk logical sector size metadata item. */
419typedef struct VhdxVDiskLogicalSectorSize *PVhdxVDiskLogicalSectorSize;
420
421/**
422 * VHDX virtual disk physical sector size.
423 */
424#pragma pack(1)
425typedef struct VhdxVDiskPhysicalSectorSize
426{
427 /** Physical sector size. */
428 uint64_t u64PhysicalSectorSize;
429} VhdxVDiskPhysicalSectorSize;
430#pragma pack()
431/** Pointer to an on disk VHDX virtual disk physical sector size metadata item. */
432typedef struct VhdxVDiskPhysicalSectorSize *PVhdxVDiskPhysicalSectorSize;
433
434/**
435 * VHDX parent locator header.
436 */
437#pragma pack(1)
438typedef struct VhdxParentLocatorHeader
439{
440 /** Locator type UUID. */
441 RTUUID UuidLocatorType;
442 /** Reserved. */
443 uint16_t u16Reserved;
444 /** Number of key value pairs. */
445 uint16_t u16KeyValueCount;
446} VhdxParentLocatorHeader;
447#pragma pack()
448/** Pointer to an on disk VHDX parent locator header metadata item. */
449typedef struct VhdxParentLocatorHeader *PVhdxParentLocatorHeader;
450
451/** VHDX parent locator type. */
452#define VHDX_PARENT_LOCATOR_TYPE_VHDX "b04aefb7-d19e-4a81-b789-25b8e9445913"
453
454/**
455 * VHDX parent locator entry.
456 */
457#pragma pack(1)
458typedef struct VhdxParentLocatorEntry
459{
460 /** Offset of the key. */
461 uint32_t u32KeyOffset;
462 /** Offset of the value. */
463 uint32_t u32ValueOffset;
464 /** Length of the key. */
465 uint16_t u16KeyLength;
466 /** Length of the value. */
467 uint16_t u16ValueLength;
468} VhdxParentLocatorEntry;
469#pragma pack()
470/** Pointer to an on disk VHDX parent locator entry. */
471typedef struct VhdxParentLocatorEntry *PVhdxParentLocatorEntry;
472
473/*******************************************************************************
474* Constants And Macros, Structures and Typedefs *
475*******************************************************************************/
476
477typedef enum VHDXMETADATAITEM
478{
479 VHDXMETADATAITEM_UNKNOWN = 0,
480 VHDXMETADATAITEM_FILE_PARAMS,
481 VHDXMETADATAITEM_VDISK_SIZE,
482 VHDXMETADATAITEM_PAGE83_DATA,
483 VHDXMETADATAITEM_LOGICAL_SECTOR_SIZE,
484 VHDXMETADATAITEM_PHYSICAL_SECTOR_SIZE,
485 VHDXMETADATAITEM_PARENT_LOCATOR,
486 VHDXMETADATAITEM_32BIT_HACK = 0x7fffffff
487} VHDXMETADATAITEM;
488
489/**
490 * Table to validate the metadata item UUIDs and the flags.
491 */
492typedef struct VHDXMETADATAITEMPROPS
493{
494 /** Item UUID. */
495 const char *pszItemUuid;
496 /** Flag whether this is a user or system metadata item. */
497 bool fIsUser;
498 /** Flag whether this is a virtual disk or file metadata item. */
499 bool fIsVDisk;
500 /** Flag whether this metadata item is required to load the file. */
501 bool fIsRequired;
502 /** Metadata item enum associated with this UUID. */
503 VHDXMETADATAITEM enmMetadataItem;
504} VHDXMETADATAITEMPROPS;
505
506/**
507 * VHDX image data structure.
508 */
509typedef struct VHDXIMAGE
510{
511 /** Image name. */
512 const char *pszFilename;
513 /** Storage handle. */
514 PVDIOSTORAGE pStorage;
515
516 /** Pointer to the per-disk VD interface list. */
517 PVDINTERFACE pVDIfsDisk;
518 /** Pointer to the per-image VD interface list. */
519 PVDINTERFACE pVDIfsImage;
520 /** Error interface. */
521 PVDINTERFACEERROR pIfError;
522 /** I/O interface. */
523 PVDINTERFACEIOINT pIfIo;
524
525 /** Open flags passed by VBoxHD layer. */
526 unsigned uOpenFlags;
527 /** Image flags defined during creation or determined during open. */
528 unsigned uImageFlags;
529 /** Version of the VHDX image format. */
530 unsigned uVersion;
531 /** Total size of the image. */
532 uint64_t cbSize;
533 /** Logical sector size of the image. */
534 size_t cbLogicalSector;
535 /** Block size of the image. */
536 size_t cbBlock;
537 /** Physical geometry of this image. */
538 VDGEOMETRY PCHSGeometry;
539 /** Logical geometry of this image. */
540 VDGEOMETRY LCHSGeometry;
541
542 /** The BAT. */
543 PVhdxBatEntry paBat;
544 /** Chunk ratio. */
545 uint32_t uChunkRatio;
546
547} VHDXIMAGE, *PVHDXIMAGE;
548
549/**
550 * Endianess conversion direction.
551 */
552typedef enum VHDXECONV
553{
554 /** Host to file endianess. */
555 VHDXECONV_H2F = 0,
556 /** File to host endianess. */
557 VHDXECONV_F2H
558} VHDXECONV;
559
560/** Macros for endianess conversion. */
561#define SET_ENDIAN_U16(u16) (enmConv == VHDXECONV_H2F ? RT_H2LE_U16(u16) : RT_LE2H_U16(u16))
562#define SET_ENDIAN_U32(u32) (enmConv == VHDXECONV_H2F ? RT_H2LE_U32(u32) : RT_LE2H_U32(u32))
563#define SET_ENDIAN_U64(u64) (enmConv == VHDXECONV_H2F ? RT_H2LE_U64(u64) : RT_LE2H_U64(u64))
564
565/*******************************************************************************
566* Static Variables *
567*******************************************************************************/
568
569/**
570 * NULL-terminated array of supported file extensions.
571 */
572static const VDFILEEXTENSION s_aVhdxFileExtensions[] =
573{
574 {"vhdx", VDTYPE_HDD},
575 {NULL, VDTYPE_INVALID}
576};
577
578/**
579 * Static table to verify the metadata item properties and the flags.
580 */
581static const VHDXMETADATAITEMPROPS s_aVhdxMetadataItemProps[] =
582{
583 /* pcszItemUuid fIsUser, fIsVDisk, fIsRequired, enmMetadataItem */
584 {VHDX_METADATA_TBL_ENTRY_ITEM_FILE_PARAMS, false, false, true, VHDXMETADATAITEM_FILE_PARAMS},
585 {VHDX_METADATA_TBL_ENTRY_ITEM_VDISK_SIZE, false, true, true, VHDXMETADATAITEM_VDISK_SIZE},
586 {VHDX_METADATA_TBL_ENTRY_ITEM_PAGE83_DATA, false, true, true, VHDXMETADATAITEM_PAGE83_DATA},
587 {VHDX_METADATA_TBL_ENTRY_ITEM_LOG_SECT_SIZE, false, true, true, VHDXMETADATAITEM_LOGICAL_SECTOR_SIZE},
588 {VHDX_METADATA_TBL_ENTRY_ITEM_PHYS_SECT_SIZE, false, true, false, VHDXMETADATAITEM_PHYSICAL_SECTOR_SIZE},
589 {VHDX_METADATA_TBL_ENTRY_ITEM_PARENT_LOCATOR, false, false, true, VHDXMETADATAITEM_PARENT_LOCATOR}
590};
591
592/*******************************************************************************
593* Internal Functions *
594*******************************************************************************/
595
596/**
597 * Converts the file identifier between file and host endianness.
598 *
599 * @returns nothing.
600 * @param enmConv Direction of the conversion.
601 * @param pFileIdentifierConv Where to store the converted file identifier.
602 * @param pFileIdentifier The file identifier to convert.
603 *
604 * @note It is safe to use the same pointer for pFileIdentifierConv and pFileIdentifier.
605 */
606DECLINLINE(void) vhdxConvFileIdentifierEndianess(VHDXECONV enmConv, PVhdxFileIdentifier pFileIdentifierConv,
607 PVhdxFileIdentifier pFileIdentifier)
608{
609 pFileIdentifierConv->u64Signature = SET_ENDIAN_U64(pFileIdentifier->u64Signature);
610 for (unsigned i = 0; i < RT_ELEMENTS(pFileIdentifierConv->awszCreator); i++)
611 pFileIdentifierConv->awszCreator[i] = SET_ENDIAN_U16(pFileIdentifier->awszCreator[i]);
612}
613
614/**
615 * Converts a UUID between file and host endianness.
616 *
617 * @returns nothing.
618 * @param enmConv Direction of the conversion.
619 * @param pUuidConv Where to store the converted UUID.
620 * @param pUuid The UUID to convert.
621 *
622 * @note It is safe to use the same pointer for pUuidConv and pUuid.
623 */
624DECLINLINE(void) vhdxConvUuidEndianess(VHDXECONV enmConv, PRTUUID pUuidConv, PRTUUID pUuid)
625{
626 pUuidConv->Gen.u32TimeLow = SET_ENDIAN_U32(pUuid->Gen.u32TimeLow);
627 pUuidConv->Gen.u16TimeMid = SET_ENDIAN_U16(pUuid->Gen.u16TimeMid);
628 pUuidConv->Gen.u16TimeHiAndVersion = SET_ENDIAN_U16(pUuid->Gen.u16TimeHiAndVersion);
629 pUuidConv->Gen.u8ClockSeqHiAndReserved = pUuid->Gen.u8ClockSeqHiAndReserved;
630 pUuidConv->Gen.u8ClockSeqLow = pUuid->Gen.u8ClockSeqLow;
631 for (unsigned i = 0; i < RT_ELEMENTS(pUuidConv->Gen.au8Node); i++)
632 pUuidConv->Gen.au8Node[i] = pUuid->Gen.au8Node[i];
633}
634
635/**
636 * Converts a VHDX header between file and host endianness.
637 *
638 * @returns nothing.
639 * @param enmConv Direction of the conversion.
640 * @param pHdrConv Where to store the converted header.
641 * @param pHdr The VHDX header to convert.
642 *
643 * @note It is safe to use the same pointer for pHdrConv and pHdr.
644 */
645DECLINLINE(void) vhdxConvHeaderEndianess(VHDXECONV enmConv, PVhdxHeader pHdrConv, PVhdxHeader pHdr)
646{
647 pHdrConv->u32Signature = SET_ENDIAN_U32(pHdr->u32Signature);
648 pHdrConv->u32Checksum = SET_ENDIAN_U32(pHdr->u32Checksum);
649 pHdrConv->u64SequenceNumber = SET_ENDIAN_U64(pHdr->u64SequenceNumber);
650 vhdxConvUuidEndianess(enmConv, &pHdrConv->UuidFileWrite, &pHdrConv->UuidFileWrite);
651 vhdxConvUuidEndianess(enmConv, &pHdrConv->UuidDataWrite, &pHdrConv->UuidDataWrite);
652 vhdxConvUuidEndianess(enmConv, &pHdrConv->UuidLog, &pHdrConv->UuidLog);
653 pHdrConv->u16LogVersion = SET_ENDIAN_U16(pHdr->u16LogVersion);
654 pHdrConv->u16Version = SET_ENDIAN_U16(pHdr->u16Version);
655 pHdrConv->u32LogLength = SET_ENDIAN_U32(pHdr->u32LogLength);
656 pHdrConv->u64LogOffset = SET_ENDIAN_U64(pHdr->u64LogOffset);
657}
658
659/**
660 * Converts a VHDX region table header between file and host endianness.
661 *
662 * @returns nothing.
663 * @param enmConv Direction of the conversion.
664 * @param pRegTblHdrConv Where to store the converted header.
665 * @param pRegTblHdr The VHDX region table header to convert.
666 *
667 * @note It is safe to use the same pointer for pRegTblHdrConv and pRegTblHdr.
668 */
669DECLINLINE(void) vhdxConvRegionTblHdrEndianess(VHDXECONV enmConv, PVhdxRegionTblHdr pRegTblHdrConv,
670 PVhdxRegionTblHdr pRegTblHdr)
671{
672 pRegTblHdrConv->u32Signature = SET_ENDIAN_U32(pRegTblHdr->u32Signature);
673 pRegTblHdrConv->u32Checksum = SET_ENDIAN_U32(pRegTblHdr->u32Checksum);
674 pRegTblHdrConv->u32EntryCount = SET_ENDIAN_U32(pRegTblHdr->u32EntryCount);
675 pRegTblHdrConv->u32Reserved = SET_ENDIAN_U32(pRegTblHdr->u32Reserved);
676}
677
678/**
679 * Converts a VHDX region table entry between file and host endianness.
680 *
681 * @returns nothing.
682 * @param enmConv Direction of the conversion.
683 * @param pRegTblEntConv Where to store the converted region table entry.
684 * @param pRegTblEnt The VHDX region table entry to convert.
685 *
686 * @note It is safe to use the same pointer for pRegTblEntConv and pRegTblEnt.
687 */
688DECLINLINE(void) vhdxConvRegionTblEntryEndianess(VHDXECONV enmConv, PVhdxRegionTblEntry pRegTblEntConv,
689 PVhdxRegionTblEntry pRegTblEnt)
690{
691 vhdxConvUuidEndianess(enmConv, &pRegTblEntConv->UuidObject, &pRegTblEnt->UuidObject);
692 pRegTblEntConv->u64FileOffset = SET_ENDIAN_U64(pRegTblEnt->u64FileOffset);
693 pRegTblEntConv->u32Length = SET_ENDIAN_U32(pRegTblEnt->u32Length);
694 pRegTblEntConv->u32Flags = SET_ENDIAN_U32(pRegTblEnt->u32Flags);
695}
696
697/**
698 * Converts a VHDX log entry header between file and host endianness.
699 *
700 * @returns nothing.
701 * @param enmConv Direction of the conversion.
702 * @param pLogEntryHdrConv Where to store the converted log entry header.
703 * @param pLogEntryHdr The VHDX log entry header to convert.
704 *
705 * @note It is safe to use the same pointer for pLogEntryHdrConv and pLogEntryHdr.
706 */
707DECLINLINE(void) vhdxConvLogEntryHdrEndianess(VHDXECONV enmConv, PVhdxLogEntryHdr pLogEntryHdrConv,
708 PVhdxLogEntryHdr pLogEntryHdr)
709{
710 pLogEntryHdrConv->u32Signature = SET_ENDIAN_U32(pLogEntryHdr->u32Signature);
711 pLogEntryHdrConv->u32Checksum = SET_ENDIAN_U32(pLogEntryHdr->u32Checksum);
712 pLogEntryHdrConv->u32EntryLength = SET_ENDIAN_U32(pLogEntryHdr->u32EntryLength);
713 pLogEntryHdrConv->u32Tail = SET_ENDIAN_U32(pLogEntryHdr->u32Tail);
714 pLogEntryHdrConv->u64SequenceNumber = SET_ENDIAN_U64(pLogEntryHdr->u64SequenceNumber);
715 pLogEntryHdrConv->u32DescriptorCount = SET_ENDIAN_U32(pLogEntryHdr->u32DescriptorCount);
716 pLogEntryHdrConv->u32Reserved = SET_ENDIAN_U32(pLogEntryHdr->u32Reserved);
717 vhdxConvUuidEndianess(enmConv, &pLogEntryHdrConv->UuidLog, &pLogEntryHdr->UuidLog);
718 pLogEntryHdrConv->u64FlushedFileOffset = SET_ENDIAN_U64(pLogEntryHdr->u64FlushedFileOffset);
719}
720
721/**
722 * Converts a VHDX log zero descriptor between file and host endianness.
723 *
724 * @returns nothing.
725 * @param enmConv Direction of the conversion.
726 * @param pLogZeroDescConv Where to store the converted log zero descriptor.
727 * @param pLogZeroDesc The VHDX log zero descriptor to convert.
728 *
729 * @note It is safe to use the same pointer for pLogZeroDescConv and pLogZeroDesc.
730 */
731DECLINLINE(void) vhdxConvLogZeroDescEndianess(VHDXECONV enmConv, PVhdxLogZeroDesc pLogZeroDescConv,
732 PVhdxLogZeroDesc pLogZeroDesc)
733{
734 pLogZeroDescConv->u32ZeroSignature = SET_ENDIAN_U32(pLogZeroDesc->u32ZeroSignature);
735 pLogZeroDescConv->u32Reserved = SET_ENDIAN_U32(pLogZeroDesc->u32Reserved);
736 pLogZeroDescConv->u64ZeroLength = SET_ENDIAN_U64(pLogZeroDesc->u64ZeroLength);
737 pLogZeroDescConv->u64FileOffset = SET_ENDIAN_U64(pLogZeroDesc->u64FileOffset);
738 pLogZeroDescConv->u64SequenceNumber = SET_ENDIAN_U64(pLogZeroDesc->u64SequenceNumber);
739}
740
741/**
742 * Converts a VHDX log data descriptor between file and host endianness.
743 *
744 * @returns nothing.
745 * @param enmConv Direction of the conversion.
746 * @param pLogDataDescConv Where to store the converted log data descriptor.
747 * @param pLogDataDesc The VHDX log data descriptor to convert.
748 *
749 * @note It is safe to use the same pointer for pLogDataDescConv and pLogDataDesc.
750 */
751DECLINLINE(void) vhdxConvLogDataDescEndianess(VHDXECONV enmConv, PVhdxLogDataDesc pLogDataDescConv,
752 PVhdxLogDataDesc pLogDataDesc)
753{
754 pLogDataDescConv->u32DataSignature = SET_ENDIAN_U32(pLogDataDesc->u32DataSignature);
755 pLogDataDescConv->u32TrailingBytes = SET_ENDIAN_U32(pLogDataDesc->u32TrailingBytes);
756 pLogDataDescConv->u64LeadingBytes = SET_ENDIAN_U64(pLogDataDesc->u64LeadingBytes);
757 pLogDataDescConv->u64FileOffset = SET_ENDIAN_U64(pLogDataDesc->u64FileOffset);
758 pLogDataDescConv->u64SequenceNumber = SET_ENDIAN_U64(pLogDataDesc->u64SequenceNumber);
759}
760
761/**
762 * Converts a VHDX log data sector between file and host endianness.
763 *
764 * @returns nothing.
765 * @param enmConv Direction of the conversion.
766 * @param pLogDataSectorConv Where to store the converted log data sector.
767 * @param pLogDataSector The VHDX log data sector to convert.
768 *
769 * @note It is safe to use the same pointer for pLogDataSectorConv and pLogDataSector.
770 */
771DECLINLINE(void) vhdxConvLogDataSectorEndianess(VHDXECONV enmConv, PVhdxLogDataSector pLogDataSectorConv,
772 PVhdxLogDataSector pLogDataSector)
773{
774 pLogDataSectorConv->u32DataSignature = SET_ENDIAN_U32(pLogDataSector->u32DataSignature);
775 pLogDataSectorConv->u32SequenceHigh = SET_ENDIAN_U32(pLogDataSector->u32SequenceHigh);
776 pLogDataSectorConv->u32SequenceLow = SET_ENDIAN_U32(pLogDataSector->u32SequenceLow);
777}
778
779/**
780 * Converts a BAT between file and host endianess.
781 *
782 * @returns nothing.
783 * @param enmConv Direction of the conversion.
784 * @param paBatEntriesConv Where to store the converted BAT.
785 * @param paBatEntries The VHDX BAT to convert.
786 *
787 * @note It is safe to use the same pointer for paBatEntriesConv and paBatEntries.
788 */
789DECLINLINE(void) vhdxConvBatTableEndianess(VHDXECONV enmConv, PVhdxBatEntry paBatEntriesConv,
790 PVhdxBatEntry paBatEntries, uint32_t cBatEntries)
791{
792 for (uint32_t i = 0; i < cBatEntries; i++)
793 paBatEntriesConv[i].u64BatEntry = SET_ENDIAN_U64(paBatEntries[i].u64BatEntry);
794}
795
796/**
797 * Converts a VHDX metadata table header between file and host endianness.
798 *
799 * @returns nothing.
800 * @param enmConv Direction of the conversion.
801 * @param pMetadataTblHdrConv Where to store the converted metadata table header.
802 * @param pMetadataTblHdr The VHDX metadata table header to convert.
803 *
804 * @note It is safe to use the same pointer for pMetadataTblHdrConv and pMetadataTblHdr.
805 */
806DECLINLINE(void) vhdxConvMetadataTblHdrEndianess(VHDXECONV enmConv, PVhdxMetadataTblHdr pMetadataTblHdrConv,
807 PVhdxMetadataTblHdr pMetadataTblHdr)
808{
809 pMetadataTblHdrConv->u64Signature = SET_ENDIAN_U64(pMetadataTblHdr->u64Signature);
810 pMetadataTblHdrConv->u16Reserved = SET_ENDIAN_U16(pMetadataTblHdr->u16Reserved);
811 pMetadataTblHdrConv->u16EntryCount = SET_ENDIAN_U16(pMetadataTblHdr->u16EntryCount);
812 for (unsigned i = 0; i < RT_ELEMENTS(pMetadataTblHdr->u32Reserved2); i++)
813 pMetadataTblHdrConv->u32Reserved2[i] = SET_ENDIAN_U32(pMetadataTblHdr->u32Reserved2[i]);
814}
815
816/**
817 * Converts a VHDX metadata table entry between file and host endianness.
818 *
819 * @returns nothing.
820 * @param enmConv Direction of the conversion.
821 * @param pMetadataTblEntryConv Where to store the converted metadata table entry.
822 * @param pMetadataTblEntry The VHDX metadata table entry to convert.
823 *
824 * @note It is safe to use the same pointer for pMetadataTblEntryConv and pMetadataTblEntry.
825 */
826DECLINLINE(void) vhdxConvMetadataTblEntryEndianess(VHDXECONV enmConv, PVhdxMetadataTblEntry pMetadataTblEntryConv,
827 PVhdxMetadataTblEntry pMetadataTblEntry)
828{
829 vhdxConvUuidEndianess(enmConv, &pMetadataTblEntryConv->UuidItem, &pMetadataTblEntry->UuidItem);
830 pMetadataTblEntryConv->u32Offset = SET_ENDIAN_U32(pMetadataTblEntry->u32Offset);
831 pMetadataTblEntryConv->u32Length = SET_ENDIAN_U32(pMetadataTblEntry->u32Length);
832 pMetadataTblEntryConv->u32Flags = SET_ENDIAN_U32(pMetadataTblEntry->u32Flags);
833 pMetadataTblEntryConv->u32Reserved = SET_ENDIAN_U32(pMetadataTblEntry->u32Reserved);
834}
835
836/**
837 * Converts a VHDX file parameters item between file and host endianness.
838 *
839 * @returns nothing.
840 * @param enmConv Direction of the conversion.
841 * @param pFileParamsConv Where to store the converted file parameters item entry.
842 * @param pFileParams The VHDX file parameters item to convert.
843 *
844 * @note It is safe to use the same pointer for pFileParamsConv and pFileParams.
845 */
846DECLINLINE(void) vhdxConvFileParamsEndianess(VHDXECONV enmConv, PVhdxFileParameters pFileParamsConv,
847 PVhdxFileParameters pFileParams)
848{
849 pFileParamsConv->u32BlockSize = SET_ENDIAN_U32(pFileParams->u32BlockSize);
850 pFileParamsConv->u32Flags = SET_ENDIAN_U32(pFileParams->u32Flags);
851}
852
853/**
854 * Converts a VHDX virtual disk size item between file and host endianness.
855 *
856 * @returns nothing.
857 * @param enmConv Direction of the conversion.
858 * @param pVDiskSizeConv Where to store the converted virtual disk size item entry.
859 * @param pVDiskSize The VHDX virtual disk size item to convert.
860 *
861 * @note It is safe to use the same pointer for pVDiskSizeConv and pVDiskSize.
862 */
863DECLINLINE(void) vhdxConvVDiskSizeEndianess(VHDXECONV enmConv, PVhdxVDiskSize pVDiskSizeConv,
864 PVhdxVDiskSize pVDiskSize)
865{
866 pVDiskSizeConv->u64VDiskSize = SET_ENDIAN_U64(pVDiskSize->u64VDiskSize);
867}
868
869/**
870 * Converts a VHDX page 83 data item between file and host endianness.
871 *
872 * @returns nothing.
873 * @param enmConv Direction of the conversion.
874 * @param pPage83DataConv Where to store the converted page 83 data item entry.
875 * @param pPage83Data The VHDX page 83 data item to convert.
876 *
877 * @note It is safe to use the same pointer for pPage83DataConv and pPage83Data.
878 */
879DECLINLINE(void) vhdxConvPage83DataEndianess(VHDXECONV enmConv, PVhdxPage83Data pPage83DataConv,
880 PVhdxPage83Data pPage83Data)
881{
882 vhdxConvUuidEndianess(enmConv, &pPage83DataConv->UuidPage83Data, &pPage83Data->UuidPage83Data);
883}
884
885/**
886 * Converts a VHDX logical sector size item between file and host endianness.
887 *
888 * @returns nothing.
889 * @param enmConv Direction of the conversion.
890 * @param pVDiskLogSectSizeConv Where to store the converted logical sector size item entry.
891 * @param pVDiskLogSectSize The VHDX logical sector size item to convert.
892 *
893 * @note It is safe to use the same pointer for pVDiskLogSectSizeConv and pVDiskLogSectSize.
894 */
895DECLINLINE(void) vhdxConvVDiskLogSectSizeEndianess(VHDXECONV enmConv, PVhdxVDiskLogicalSectorSize pVDiskLogSectSizeConv,
896 PVhdxVDiskLogicalSectorSize pVDiskLogSectSize)
897{
898 pVDiskLogSectSizeConv->u32LogicalSectorSize = SET_ENDIAN_U32(pVDiskLogSectSize->u32LogicalSectorSize);
899}
900
901/**
902 * Converts a VHDX physical sector size item between file and host endianness.
903 *
904 * @returns nothing.
905 * @param enmConv Direction of the conversion.
906 * @param pVDiskPhysSectSizeConv Where to store the converted physical sector size item entry.
907 * @param pVDiskPhysSectSize The VHDX physical sector size item to convert.
908 *
909 * @note It is safe to use the same pointer for pVDiskPhysSectSizeConv and pVDiskPhysSectSize.
910 */
911DECLINLINE(void) vhdxConvVDiskPhysSectSizeEndianess(VHDXECONV enmConv, PVhdxVDiskPhysicalSectorSize pVDiskPhysSectSizeConv,
912 PVhdxVDiskPhysicalSectorSize pVDiskPhysSectSize)
913{
914 pVDiskPhysSectSizeConv->u64PhysicalSectorSize = SET_ENDIAN_U64(pVDiskPhysSectSize->u64PhysicalSectorSize);
915}
916
917/**
918 * Converts a VHDX parent locator header item between file and host endianness.
919 *
920 * @returns nothing.
921 * @param enmConv Direction of the conversion.
922 * @param pParentLocatorHdrConv Where to store the converted parent locator header item entry.
923 * @param pParentLocatorHdr The VHDX parent locator header item to convert.
924 *
925 * @note It is safe to use the same pointer for pParentLocatorHdrConv and pParentLocatorHdr.
926 */
927DECLINLINE(void) vhdxConvParentLocatorHeaderEndianness(VHDXECONV enmConv, PVhdxParentLocatorHeader pParentLocatorHdrConv,
928 PVhdxParentLocatorHeader pParentLocatorHdr)
929{
930 vhdxConvUuidEndianess(enmConv, &pParentLocatorHdrConv->UuidLocatorType, &pParentLocatorHdr->UuidLocatorType);
931 pParentLocatorHdrConv->u16Reserved = SET_ENDIAN_U16(pParentLocatorHdr->u16Reserved);
932 pParentLocatorHdrConv->u16KeyValueCount = SET_ENDIAN_U16(pParentLocatorHdr->u16KeyValueCount);
933}
934
935/**
936 * Converts a VHDX parent locator entry between file and host endianness.
937 *
938 * @returns nothing.
939 * @param enmConv Direction of the conversion.
940 * @param pParentLocatorEntryConv Where to store the converted parent locator entry.
941 * @param pParentLocatorEntry The VHDX parent locator entry to convert.
942 *
943 * @note It is safe to use the same pointer for pParentLocatorEntryConv and pParentLocatorEntry.
944 */
945DECLINLINE(void) vhdxConvParentLocatorEntryEndianess(VHDXECONV enmConv, PVhdxParentLocatorEntry pParentLocatorEntryConv,
946 PVhdxParentLocatorEntry pParentLocatorEntry)
947{
948 pParentLocatorEntryConv->u32KeyOffset = SET_ENDIAN_U32(pParentLocatorEntry->u32KeyOffset);
949 pParentLocatorEntryConv->u32ValueOffset = SET_ENDIAN_U32(pParentLocatorEntry->u32ValueOffset);
950 pParentLocatorEntryConv->u16KeyLength = SET_ENDIAN_U16(pParentLocatorEntry->u16KeyLength);
951 pParentLocatorEntryConv->u16ValueLength = SET_ENDIAN_U16(pParentLocatorEntry->u16ValueLength);
952}
953
954/**
955 * Internal. Free all allocated space for representing an image except pImage,
956 * and optionally delete the image from disk.
957 */
958static int vhdxFreeImage(PVHDXIMAGE pImage, bool fDelete)
959{
960 int rc = VINF_SUCCESS;
961
962 /* Freeing a never allocated image (e.g. because the open failed) is
963 * not signalled as an error. After all nothing bad happens. */
964 if (pImage)
965 {
966 if (pImage->pStorage)
967 {
968 vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
969 pImage->pStorage = NULL;
970 }
971
972 if (pImage->paBat)
973 {
974 RTMemFree(pImage->paBat);
975 pImage->paBat = NULL;
976 }
977
978 if (fDelete && pImage->pszFilename)
979 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
980 }
981
982 LogFlowFunc(("returns %Rrc\n", rc));
983 return rc;
984}
985
986/**
987 * Loads all required fields from the given VHDX header.
988 * The header must be converted to the host endianess and validated already.
989 *
990 * @returns VBox status code.
991 * @param pImage Image instance data.
992 * @param pHdr The header to load.
993 */
994static int vhdxLoadHeader(PVHDXIMAGE pImage, PVhdxHeader pHdr)
995{
996 int rc = VINF_SUCCESS;
997
998 LogFlowFunc(("pImage=%#p pHdr=%#p\n", pImage, pHdr));
999
1000 /*
1001 * Most fields in the header are not required because the backend implements
1002 * readonly access only so far.
1003 * We just have to check that the log is empty, we have to refuse to load the
1004 * image otherwsie because replaying the log is not implemented.
1005 */
1006 if (pHdr->u16Version == VHDX_HEADER_VHDX_VERSION)
1007 {
1008 /* Check that the log UUID is zero. */
1009 pImage->uVersion = pHdr->u16Version;
1010 if (!RTUuidIsNull(&pHdr->UuidLog))
1011 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1012 "VHDX: Image \'%s\' has a non empty log which is not supported",
1013 pImage->pszFilename);
1014 }
1015 else
1016 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1017 "VHDX: Image \'%s\' uses an unsupported version (%u) of the VHDX format",
1018 pImage->pszFilename, pHdr->u16Version);
1019
1020 LogFlowFunc(("return rc=%Rrc\n", rc));
1021 return rc;
1022}
1023
1024/**
1025 * Determines the current header and loads it.
1026 *
1027 * @returns VBox status code.
1028 * @param pImage Image instance data.
1029 */
1030static int vhdxFindAndLoadCurrentHeader(PVHDXIMAGE pImage)
1031{
1032 VhdxHeader Hdr1, Hdr2;
1033 uint32_t u32ChkSum = 0;
1034 uint32_t u32ChkSumSaved = 0;
1035 bool fHdr1Valid = false;
1036 bool fHdr2Valid = false;
1037 int rc = VINF_SUCCESS;
1038
1039 LogFlowFunc(("pImage=%#p\n", pImage));
1040
1041 /*
1042 * The VHDX format defines two headers at different offsets to provide failure
1043 * consistency. Only one header is current. This can be determined using the
1044 * sequence number and checksum fields in the header.
1045 */
1046
1047 /* Read the first header. */
1048 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, VHDX_HEADER1_OFFSET,
1049 &Hdr1, sizeof(Hdr1), NULL);
1050 if (RT_SUCCESS(rc))
1051 {
1052 vhdxConvHeaderEndianess(VHDXECONV_F2H, &Hdr1, &Hdr1);
1053
1054 /* Validate checksum. */
1055 u32ChkSumSaved = Hdr1.u32Checksum;
1056 Hdr1.u32Checksum = 0;
1057 //u32ChkSum = RTCrc32C(&Hdr1, sizeof(Hdr1));
1058
1059 if ( Hdr1.u32Signature == VHDX_HEADER_SIGNATURE
1060 /*&& u32ChkSum == u32ChkSumSaved*/)
1061 fHdr1Valid = true;
1062 }
1063
1064 /* Try to read the second header in any case (even if reading the first failed). */
1065 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, VHDX_HEADER2_OFFSET,
1066 &Hdr2, sizeof(Hdr2), NULL);
1067 if (RT_SUCCESS(rc))
1068 {
1069 vhdxConvHeaderEndianess(VHDXECONV_F2H, &Hdr2, &Hdr2);
1070
1071 /* Validate checksum. */
1072 u32ChkSumSaved = Hdr2.u32Checksum;
1073 Hdr2.u32Checksum = 0;
1074 //u32ChkSum = RTCrc32C(&Hdr2, sizeof(Hdr2));
1075
1076 if ( Hdr2.u32Signature == VHDX_HEADER_SIGNATURE
1077 /*&& u32ChkSum == u32ChkSumSaved*/)
1078 fHdr2Valid = true;
1079 }
1080
1081 /* Determine the current header. */
1082 if (fHdr1Valid != fHdr2Valid)
1083 {
1084 /* Only one header is valid - use it. */
1085 rc = vhdxLoadHeader(pImage, fHdr1Valid ? &Hdr1 : &Hdr2);
1086 }
1087 else if (!fHdr1Valid && !fHdr2Valid)
1088 {
1089 /* Crap, both headers are corrupt, refuse to load the image. */
1090 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1091 "VHDX: Can not load the image because both headers are corrupt");
1092 }
1093 else
1094 {
1095 /* Both headers are valid. Use the sequence number to find the current one. */
1096 if (Hdr1.u64SequenceNumber > Hdr2.u64SequenceNumber)
1097 rc = vhdxLoadHeader(pImage, &Hdr1);
1098 else
1099 rc = vhdxLoadHeader(pImage, &Hdr2);
1100 }
1101
1102 LogFlowFunc(("returns rc=%Rrc\n", rc));
1103 return rc;
1104}
1105
1106/**
1107 * Loads the BAT region.
1108 *
1109 * @returns VBox status code.
1110 * @param pImage Image instance data.
1111 * @param offRegion Start offset of the region.
1112 * @param cbRegion Size of the region.
1113 */
1114static int vhdxLoadBatRegion(PVHDXIMAGE pImage, uint64_t offRegion,
1115 size_t cbRegion)
1116{
1117 int rc = VINF_SUCCESS;
1118 uint32_t cDataBlocks;
1119 uint32_t uChunkRatio;
1120 uint32_t cSectorBitmapBlocks;
1121 uint32_t cBatEntries;
1122 uint32_t cbBatEntries;
1123 PVhdxBatEntry paBatEntries = NULL;
1124
1125 LogFlowFunc(("pImage=%#p\n", pImage));
1126
1127 /* Calculate required values first. */
1128 uChunkRatio = (RT_BIT_64(23) * pImage->cbLogicalSector) / pImage->cbBlock;
1129 cDataBlocks = pImage->cbSize / pImage->cbBlock;
1130 if (pImage->cbSize % pImage->cbBlock)
1131 cDataBlocks++;
1132
1133 cSectorBitmapBlocks = cDataBlocks / uChunkRatio;
1134 if (cDataBlocks % uChunkRatio)
1135 cSectorBitmapBlocks++;
1136
1137 cBatEntries = cDataBlocks + (cDataBlocks - 1)/uChunkRatio;
1138 cbBatEntries = cBatEntries * sizeof(VhdxBatEntry);
1139
1140 if (cbBatEntries <= cbRegion)
1141 {
1142 /*
1143 * Load the complete BAT region first, convert to host endianess and process
1144 * it afterwards. The SB entries can be removed because they are not needed yet.
1145 */
1146 paBatEntries = (PVhdxBatEntry)RTMemAlloc(cbBatEntries);
1147 if (paBatEntries)
1148 {
1149 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offRegion,
1150 paBatEntries, cbBatEntries, NULL);
1151 if (RT_SUCCESS(rc))
1152 {
1153 vhdxConvBatTableEndianess(VHDXECONV_F2H, paBatEntries, paBatEntries,
1154 cBatEntries);
1155
1156 /* Go through the table and validate it. */
1157 for (unsigned i = 0; i < cBatEntries; i++)
1158 {
1159 if ( i != 0
1160 && (i % uChunkRatio) == 0)
1161 {
1162 /* Sector bitmap block. */
1163 if ( VHDX_BAT_ENTRY_GET_STATE(paBatEntries[i].u64BatEntry)
1164 != VHDX_BAT_ENTRY_SB_BLOCK_NOT_PRESENT)
1165 {
1166 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1167 "VHDX: Sector bitmap block at entry %u of image \'%s\' marked as present, violation of the specification",
1168 i, pImage->pszFilename);
1169 break;
1170 }
1171 }
1172 else
1173 {
1174 /* Payload block. */
1175 if ( VHDX_BAT_ENTRY_GET_STATE(paBatEntries[i].u64BatEntry)
1176 == VHDX_BAT_ENTRY_PAYLOAD_BLOCK_PARTIALLY_PRESENT)
1177 {
1178 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1179 "VHDX: Payload block at entry %u of image \'%s\' marked as partially present, violation of the specification",
1180 i, pImage->pszFilename);
1181 break;
1182 }
1183 }
1184 }
1185
1186 if (RT_SUCCESS(rc))
1187 {
1188 pImage->paBat = paBatEntries;
1189 pImage->uChunkRatio = uChunkRatio;
1190 }
1191 }
1192 else
1193 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1194 "VHDX: Error reading the BAT from image \'%s\'",
1195 pImage->pszFilename);
1196 }
1197 else
1198 rc = vdIfError(pImage->pIfError, VERR_NO_MEMORY, RT_SRC_POS,
1199 "VHDX: Out of memory allocating memory for %u BAT entries of image \'%s\'",
1200 cBatEntries);
1201 }
1202 else
1203 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1204 "VHDX: Mismatch between calculated number of BAT entries and region size (expected %u got %u) for image \'%s\'",
1205 cbBatEntries, cbRegion, pImage->pszFilename);
1206
1207 if ( RT_FAILURE(rc)
1208 && paBatEntries)
1209 RTMemFree(paBatEntries);
1210
1211 LogFlowFunc(("returns rc=%Rrc\n", rc));
1212 return rc;
1213}
1214
1215/**
1216 * Load the file parameters metadata item from the file.
1217 *
1218 * @returns VBox status code.
1219 * @param pImage Image instance data.
1220 * @param offItem File offset where the data is stored.
1221 * @param cbItem Size of the item in the file.
1222 */
1223static int vhdxLoadFileParametersMetadata(PVHDXIMAGE pImage, uint64_t offItem, size_t cbItem)
1224{
1225 int rc = VINF_SUCCESS;
1226
1227 LogFlowFunc(("pImage=%#p offItem=%llu cbItem=%zu\n", pImage, offItem, cbItem));
1228
1229 if (cbItem != sizeof(VhdxFileParameters))
1230 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1231 "VHDX: File parameters item size mismatch (expected %u got %zu) in image \'%s\'",
1232 sizeof(VhdxFileParameters), cbItem, pImage->pszFilename);
1233 else
1234 {
1235 VhdxFileParameters FileParameters;
1236
1237 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offItem,
1238 &FileParameters, sizeof(FileParameters), NULL);
1239 if (RT_SUCCESS(rc))
1240 {
1241 vhdxConvFileParamsEndianess(VHDXECONV_F2H, &FileParameters, &FileParameters);
1242 pImage->cbBlock = FileParameters.u32BlockSize;
1243
1244 /* @todo: No support for differencing images yet. */
1245 if (FileParameters.u32Flags & VHDX_FILE_PARAMETERS_FLAGS_HAS_PARENT)
1246 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1247 "VHDX: Image \'%s\' is a differencing image which is not supported yet",
1248 pImage->pszFilename);
1249 }
1250 else
1251 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1252 "VHDX: Reading the file parameters metadata item from image \'%s\' failed",
1253 pImage->pszFilename);
1254 }
1255
1256 LogFlowFunc(("returns rc=%Rrc\n", rc));
1257 return rc;
1258}
1259
1260/**
1261 * Load the virtual disk size metadata item from the file.
1262 *
1263 * @returns VBox status code.
1264 * @param pImage Image instance data.
1265 * @param offItem File offset where the data is stored.
1266 * @param cbItem Size of the item in the file.
1267 */
1268static int vhdxLoadVDiskSizeMetadata(PVHDXIMAGE pImage, uint64_t offItem, size_t cbItem)
1269{
1270 int rc = VINF_SUCCESS;
1271
1272 LogFlowFunc(("pImage=%#p offItem=%llu cbItem=%zu\n", pImage, offItem, cbItem));
1273
1274 if (cbItem != sizeof(VhdxVDiskSize))
1275 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1276 "VHDX: Virtual disk size item size mismatch (expected %u got %zu) in image \'%s\'",
1277 sizeof(VhdxVDiskSize), cbItem, pImage->pszFilename);
1278 else
1279 {
1280 VhdxVDiskSize VDiskSize;
1281
1282 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offItem,
1283 &VDiskSize, sizeof(VDiskSize), NULL);
1284 if (RT_SUCCESS(rc))
1285 {
1286 vhdxConvVDiskSizeEndianess(VHDXECONV_F2H, &VDiskSize, &VDiskSize);
1287 pImage->cbSize = VDiskSize.u64VDiskSize;
1288 }
1289 else
1290 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1291 "VHDX: Reading the virtual disk size metadata item from image \'%s\' failed",
1292 pImage->pszFilename);
1293 }
1294
1295 LogFlowFunc(("returns rc=%Rrc\n", rc));
1296 return rc;
1297}
1298
1299/**
1300 * Load the logical sector size metadata item from the file.
1301 *
1302 * @returns VBox status code.
1303 * @param pImage Image instance data.
1304 * @param offItem File offset where the data is stored.
1305 * @param cbItem Size of the item in the file.
1306 */
1307static int vhdxLoadVDiskLogSectorSizeMetadata(PVHDXIMAGE pImage, uint64_t offItem, size_t cbItem)
1308{
1309 int rc = VINF_SUCCESS;
1310
1311 LogFlowFunc(("pImage=%#p offItem=%llu cbItem=%zu\n", pImage, offItem, cbItem));
1312
1313 if (cbItem != sizeof(VhdxVDiskLogicalSectorSize))
1314 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1315 "VHDX: Virtual disk logical sector size item size mismatch (expected %u got %zu) in image \'%s\'",
1316 sizeof(VhdxVDiskLogicalSectorSize), cbItem, pImage->pszFilename);
1317 else
1318 {
1319 VhdxVDiskLogicalSectorSize VDiskLogSectSize;
1320
1321 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offItem,
1322 &VDiskLogSectSize, sizeof(VDiskLogSectSize), NULL);
1323 if (RT_SUCCESS(rc))
1324 {
1325 vhdxConvVDiskLogSectSizeEndianess(VHDXECONV_F2H, &VDiskLogSectSize,
1326 &VDiskLogSectSize);
1327 pImage->cbLogicalSector = VDiskLogSectSize.u32LogicalSectorSize;
1328 }
1329 else
1330 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1331 "VHDX: Reading the virtual disk logical sector size metadata item from image \'%s\' failed",
1332 pImage->pszFilename);
1333 }
1334
1335 LogFlowFunc(("returns rc=%Rrc\n", rc));
1336 return rc;
1337}
1338
1339/**
1340 * Loads the metadata region.
1341 *
1342 * @returns VBox status code.
1343 * @param pImage Image instance data.
1344 * @param offRegion Start offset of the region.
1345 * @param cbRegion Size of the region.
1346 */
1347static int vhdxLoadMetadataRegion(PVHDXIMAGE pImage, uint64_t offRegion,
1348 size_t cbRegion)
1349{
1350 VhdxMetadataTblHdr MetadataTblHdr;
1351 int rc = VINF_SUCCESS;
1352
1353 LogFlowFunc(("pImage=%#p\n", pImage));
1354
1355 /* Load the header first. */
1356 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offRegion,
1357 &MetadataTblHdr, sizeof(MetadataTblHdr), NULL);
1358 if (RT_SUCCESS(rc))
1359 {
1360 vhdxConvMetadataTblHdrEndianess(VHDXECONV_F2H, &MetadataTblHdr, &MetadataTblHdr);
1361
1362 /* Validate structure. */
1363 if (MetadataTblHdr.u64Signature != VHDX_METADATA_TBL_HDR_SIGNATURE)
1364 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1365 "VHDX: Incorrect metadata table header signature for image \'%s\'",
1366 pImage->pszFilename);
1367 else if (MetadataTblHdr.u16EntryCount > VHDX_METADATA_TBL_HDR_ENTRY_COUNT_MAX)
1368 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1369 "VHDX: Incorrect entry count in metadata table header of image \'%s\'",
1370 pImage->pszFilename);
1371 else if (cbRegion < (MetadataTblHdr.u16EntryCount * sizeof(VhdxMetadataTblEntry) + sizeof(VhdxMetadataTblHdr)))
1372 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1373 "VHDX: Metadata table of image \'%s\' exceeds region size",
1374 pImage->pszFilename);
1375
1376 if (RT_SUCCESS(rc))
1377 {
1378 uint64_t offMetadataTblEntry = offRegion + sizeof(VhdxMetadataTblHdr);
1379
1380 for (unsigned i = 0; i < MetadataTblHdr.u16EntryCount; i++)
1381 {
1382 uint64_t offMetadataItem = 0;
1383 VHDXMETADATAITEM enmMetadataItem = VHDXMETADATAITEM_UNKNOWN;
1384 VhdxMetadataTblEntry MetadataTblEntry;
1385
1386 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offMetadataTblEntry,
1387 &MetadataTblEntry, sizeof(MetadataTblEntry), NULL);
1388 if (RT_FAILURE(rc))
1389 {
1390 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1391 "VHDX: Reading metadata table entry from image \'%s\' failed",
1392 pImage->pszFilename);
1393 break;
1394 }
1395
1396 vhdxConvMetadataTblEntryEndianess(VHDXECONV_F2H, &MetadataTblEntry, &MetadataTblEntry);
1397
1398 /* Check whether the flags match the expectations. */
1399 for (unsigned idxProp = 0; idxProp < RT_ELEMENTS(s_aVhdxMetadataItemProps); idxProp++)
1400 {
1401 if (!RTUuidCompareStr(&MetadataTblEntry.UuidItem,
1402 s_aVhdxMetadataItemProps[idxProp].pszItemUuid))
1403 {
1404 if ( !!(MetadataTblEntry.u32Flags & VHDX_METADATA_TBL_ENTRY_FLAGS_IS_USER)
1405 != s_aVhdxMetadataItemProps[idxProp].fIsUser)
1406 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1407 "VHDX: User flag of metadata item does not meet expectations \'%s\'",
1408 pImage->pszFilename);
1409 else if ( !!(MetadataTblEntry.u32Flags & VHDX_METADATA_TBL_ENTRY_FLAGS_IS_VDISK)
1410 != s_aVhdxMetadataItemProps[idxProp].fIsVDisk)
1411 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1412 "VHDX: Virtual disk flag of metadata item does not meet expectations \'%s\'",
1413 pImage->pszFilename);
1414 else if ( !!(MetadataTblEntry.u32Flags & VHDX_METADATA_TBL_ENTRY_FLAGS_IS_REQUIRED)
1415 != s_aVhdxMetadataItemProps[idxProp].fIsRequired)
1416 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1417 "VHDX: Required flag of metadata item does not meet expectations \'%s\'",
1418 pImage->pszFilename);
1419 else
1420 enmMetadataItem = s_aVhdxMetadataItemProps[idxProp].enmMetadataItem;
1421
1422 break;
1423 }
1424 }
1425
1426 if (RT_FAILURE(rc))
1427 break;
1428
1429 offMetadataItem = offRegion + MetadataTblEntry.u32Offset;
1430
1431 switch (enmMetadataItem)
1432 {
1433 case VHDXMETADATAITEM_FILE_PARAMS:
1434 {
1435 rc = vhdxLoadFileParametersMetadata(pImage, offMetadataItem,
1436 MetadataTblEntry.u32Length);
1437 break;
1438 }
1439 case VHDXMETADATAITEM_VDISK_SIZE:
1440 {
1441 rc = vhdxLoadVDiskSizeMetadata(pImage, offMetadataItem,
1442 MetadataTblEntry.u32Length);
1443 break;
1444 }
1445 case VHDXMETADATAITEM_PAGE83_DATA:
1446 {
1447 /*
1448 * Nothing to do here for now (marked as required but
1449 * there is no API to pass this information to the caller)
1450 * so far.
1451 */
1452 break;
1453 }
1454 case VHDXMETADATAITEM_LOGICAL_SECTOR_SIZE:
1455 {
1456 rc = vhdxLoadVDiskLogSectorSizeMetadata(pImage, offMetadataItem,
1457 MetadataTblEntry.u32Length);
1458 break;
1459 }
1460 case VHDXMETADATAITEM_PHYSICAL_SECTOR_SIZE:
1461 {
1462 /*
1463 * Nothing to do here for now (marked as required but
1464 * there is no API to pass this information to the caller)
1465 * so far.
1466 */
1467 break;
1468 }
1469 case VHDXMETADATAITEM_PARENT_LOCATOR:
1470 {
1471 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1472 "VHDX: Image \'%s\' is a differencing image which is not supported yet",
1473 pImage->pszFilename);
1474 break;
1475 }
1476 case VHDXMETADATAITEM_UNKNOWN:
1477 default:
1478 if (MetadataTblEntry.u32Flags & VHDX_METADATA_TBL_ENTRY_FLAGS_IS_REQUIRED)
1479 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1480 "VHDX: Unsupported but required metadata item in image \'%s\'",
1481 pImage->pszFilename);
1482 }
1483
1484 if (RT_FAILURE(rc))
1485 break;
1486
1487 offMetadataTblEntry += sizeof(MetadataTblEntry);
1488 }
1489 }
1490 }
1491 else
1492 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1493 "VHDX: Reading the metadata table header for image \'%s\' failed",
1494 pImage->pszFilename);
1495
1496 LogFlowFunc(("returns rc=%Rrc\n", rc));
1497 return rc;
1498}
1499
1500/**
1501 * Loads the region table and the associated regions.
1502 *
1503 * @returns VBox status code.
1504 * @param pImage Image instance data.
1505 */
1506static int vhdxLoadRegionTable(PVHDXIMAGE pImage)
1507{
1508 uint8_t *pbRegionTbl = NULL;
1509 int rc = VINF_SUCCESS;
1510
1511 LogFlowFunc(("pImage=%#p\n", pImage));
1512
1513 /* Load the complete region table into memory. */
1514 pbRegionTbl = (uint8_t *)RTMemTmpAlloc(VHDX_REGION_TBL_SIZE_MAX);
1515 if (pbRegionTbl)
1516 {
1517 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, VHDX_REGION_TBL_HDR_OFFSET,
1518 pbRegionTbl, VHDX_REGION_TBL_SIZE_MAX, NULL);
1519 if (RT_SUCCESS(rc))
1520 {
1521 PVhdxRegionTblHdr pRegionTblHdr;
1522 VhdxRegionTblHdr RegionTblHdr;
1523 uint32_t u32ChkSumSaved = 0;
1524 uint32_t u32ChkSum = 0;
1525
1526 /*
1527 * Copy the region table header to a dedicated structure where we can
1528 * convert it to host endianess.
1529 */
1530 memcpy(&RegionTblHdr, pbRegionTbl, sizeof(RegionTblHdr));
1531 vhdxConvRegionTblHdrEndianess(VHDXECONV_F2H, &RegionTblHdr, &RegionTblHdr);
1532
1533 /* Set checksum field to 0 during crc computation. */
1534 pRegionTblHdr = (PVhdxRegionTblHdr)pbRegionTbl;
1535 pRegionTblHdr->u32Checksum = 0;
1536
1537 /* Verify the region table integrity. */
1538 //u32ChkSum = RTCrc32C(pbRegionTbl, VHDX_REGION_TBL_SIZE_MAX);
1539
1540 if (RegionTblHdr.u32Signature != VHDX_REGION_TBL_HDR_SIGNATURE)
1541 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1542 "VHDX: Invalid signature for region table header of image \'%s\'",
1543 pImage->pszFilename);
1544#if 0
1545 else if (u32ChkSum != RegionTblHdr.u32Checksum)
1546 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1547 "VHDX: CRC32 checksum mismatch for the region table of image \'%s\' (expected %#x got %#x)",
1548 pImage->pszFilename, RegionTblHdr.u32Checksum, u32ChkSum);
1549#endif
1550 else if (RegionTblHdr.u32EntryCount > VHDX_REGION_TBL_HDR_ENTRY_COUNT_MAX)
1551 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1552 "VHDX: Invalid entry count field in the region table header of image \'%s\'",
1553 pImage->pszFilename);
1554
1555 if (RT_SUCCESS(rc))
1556 {
1557 /* Parse the region table entries. */
1558 PVhdxRegionTblEntry pRegTblEntry = (PVhdxRegionTblEntry)(pbRegionTbl + sizeof(VhdxRegionTblHdr));
1559 VhdxRegionTblEntry RegTblEntryBat; /**<< BAT region table entry. */
1560 bool fBatRegPresent = false;
1561
1562 for (unsigned i = 0; i < RegionTblHdr.u32EntryCount; i++)
1563 {
1564 vhdxConvRegionTblEntryEndianess(VHDXECONV_F2H, pRegTblEntry, pRegTblEntry);
1565
1566 /* Check the uuid for known regions. */
1567 if (!RTUuidCompareStr(&pRegTblEntry->UuidObject, VHDX_REGION_TBL_ENTRY_UUID_BAT))
1568 {
1569 /*
1570 * Save the BAT region and process it later.
1571 * It may come before the metadata region but needs the block size.
1572 */
1573 if (pRegTblEntry->u32Flags & VHDX_REGION_TBL_ENTRY_FLAGS_IS_REQUIRED)
1574 {
1575 fBatRegPresent = true;
1576 RegTblEntryBat.u32Length = pRegTblEntry->u32Length;
1577 RegTblEntryBat.u64FileOffset = pRegTblEntry->u64FileOffset;
1578 }
1579 else
1580 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1581 "VHDX: BAT region not marked as required in image \'%s\'",
1582 pImage->pszFilename);
1583 }
1584 else if (!RTUuidCompareStr(&pRegTblEntry->UuidObject, VHDX_REGION_TBL_ENTRY_UUID_METADATA))
1585 {
1586 if (pRegTblEntry->u32Flags & VHDX_REGION_TBL_ENTRY_FLAGS_IS_REQUIRED)
1587 rc = vhdxLoadMetadataRegion(pImage, pRegTblEntry->u64FileOffset, pRegTblEntry->u32Length);
1588 else
1589 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1590 "VHDX: Metadata region not marked as required in image \'%s\'",
1591 pImage->pszFilename);
1592 }
1593 else if (pRegTblEntry->u32Flags & VHDX_REGION_TBL_ENTRY_FLAGS_IS_REQUIRED)
1594 {
1595 /* The region is not known but marked as required, fail to load the image. */
1596 rc = vdIfError(pImage->pIfError, VERR_NOT_SUPPORTED, RT_SRC_POS,
1597 "VHDX: Unknown required region in image \'%s\'",
1598 pImage->pszFilename);
1599 }
1600
1601 if (RT_FAILURE(rc))
1602 break;
1603
1604 pRegTblEntry++;
1605 }
1606
1607 if (fBatRegPresent)
1608 rc = vhdxLoadBatRegion(pImage, RegTblEntryBat.u64FileOffset, RegTblEntryBat.u32Length);
1609 else
1610 rc = vdIfError(pImage->pIfError, VERR_VD_GEN_INVALID_HEADER, RT_SRC_POS,
1611 "VHDX: BAT region in image \'%s\' is missing",
1612 pImage->pszFilename);
1613 }
1614 }
1615 else
1616 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1617 "VHDX: Reading the region table for image \'%s\' failed",
1618 pImage->pszFilename);
1619 }
1620 else
1621 rc = vdIfError(pImage->pIfError, VERR_NO_MEMORY, RT_SRC_POS,
1622 "VHDX: Out of memory allocating memory for the region table of image \'%s\'",
1623 pImage->pszFilename);
1624
1625 if (pbRegionTbl)
1626 RTMemTmpFree(pbRegionTbl);
1627
1628 LogFlowFunc(("returns rc=%Rrc\n", rc));
1629 return rc;
1630}
1631
1632/**
1633 * Internal: Open an image, constructing all necessary data structures.
1634 */
1635static int vhdxOpenImage(PVHDXIMAGE pImage, unsigned uOpenFlags)
1636{
1637 uint64_t cbFile = 0;
1638 VhdxFileIdentifier FileIdentifier;
1639 int rc = VINF_SUCCESS;
1640
1641 LogFlowFunc(("pImage=%#p uOpenFlags=%#x\n", pImage, uOpenFlags));
1642 pImage->uOpenFlags = uOpenFlags;
1643
1644 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
1645 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
1646 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
1647
1648#if 0
1649 /* Refuse write access, it is not implemented so far. */
1650 if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
1651 return VERR_NOT_SUPPORTED;
1652#endif
1653
1654 /*
1655 * Open the image.
1656 */
1657 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
1658 VDOpenFlagsToFileOpenFlags(uOpenFlags,
1659 false /* fCreate */),
1660 &pImage->pStorage);
1661
1662 /* Do NOT signal an appropriate error here, as the VD layer has the
1663 * choice of retrying the open if it failed. */
1664 if (RT_SUCCESS(rc))
1665 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
1666
1667 if (RT_SUCCESS(rc))
1668 {
1669 if (cbFile > sizeof(FileIdentifier))
1670 {
1671 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, VHDX_FILE_IDENTIFIER_OFFSET,
1672 &FileIdentifier, sizeof(FileIdentifier), NULL);
1673 if (RT_SUCCESS(rc))
1674 {
1675 vhdxConvFileIdentifierEndianess(VHDXECONV_F2H, &FileIdentifier,
1676 &FileIdentifier);
1677 if (FileIdentifier.u64Signature != VHDX_FILE_IDENTIFIER_SIGNATURE)
1678 rc = VERR_VD_GEN_INVALID_HEADER;
1679 else
1680 rc = vhdxFindAndLoadCurrentHeader(pImage);
1681
1682 /* Load the region table. */
1683 if (RT_SUCCESS(rc))
1684 rc = vhdxLoadRegionTable(pImage);
1685 }
1686 }
1687 else
1688 rc = VERR_VD_GEN_INVALID_HEADER;
1689 }
1690
1691 if (RT_FAILURE(rc))
1692 vhdxFreeImage(pImage, false);
1693
1694 LogFlowFunc(("returns rc=%Rrc\n", rc));
1695 return rc;
1696}
1697
1698
1699/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
1700static int vhdxCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
1701 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
1702{
1703 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
1704 PVDIOSTORAGE pStorage = NULL;
1705 uint64_t cbFile;
1706 int rc = VINF_SUCCESS;
1707 VhdxFileIdentifier FileIdentifier;
1708
1709 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
1710 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
1711
1712 if ( !VALID_PTR(pszFilename)
1713 || !*pszFilename)
1714 rc = VERR_INVALID_PARAMETER;
1715 else
1716 {
1717 /*
1718 * Open the file and read the file identifier.
1719 */
1720 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
1721 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
1722 false /* fCreate */),
1723 &pStorage);
1724 if (RT_SUCCESS(rc))
1725 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
1726
1727 if (RT_SUCCESS(rc))
1728 {
1729 if (cbFile > sizeof(FileIdentifier))
1730 {
1731 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, VHDX_FILE_IDENTIFIER_OFFSET,
1732 &FileIdentifier, sizeof(FileIdentifier), NULL);
1733 if (RT_SUCCESS(rc))
1734 {
1735 vhdxConvFileIdentifierEndianess(VHDXECONV_F2H, &FileIdentifier,
1736 &FileIdentifier);
1737 if (FileIdentifier.u64Signature != VHDX_FILE_IDENTIFIER_SIGNATURE)
1738 rc = VERR_VD_GEN_INVALID_HEADER;
1739 else
1740 *penmType = VDTYPE_HDD;
1741 }
1742 }
1743 else
1744 rc = VERR_VD_GEN_INVALID_HEADER;
1745 }
1746
1747 if (pStorage)
1748 vdIfIoIntFileClose(pIfIo, pStorage);
1749 }
1750
1751 LogFlowFunc(("returns %Rrc\n", rc));
1752 return rc;
1753}
1754
1755/** @copydoc VBOXHDDBACKEND::pfnOpen */
1756static int vhdxOpen(const char *pszFilename, unsigned uOpenFlags,
1757 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
1758 VDTYPE enmType, void **ppBackendData)
1759{
1760 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
1761 int rc;
1762 PVHDXIMAGE pImage;
1763
1764 /* Check open flags. All valid flags are supported. */
1765 if ( uOpenFlags & ~VD_OPEN_FLAGS_MASK
1766 || !VALID_PTR(pszFilename)
1767 || !*pszFilename)
1768 rc = VERR_INVALID_PARAMETER;
1769 else
1770 {
1771 pImage = (PVHDXIMAGE)RTMemAllocZ(sizeof(VHDXIMAGE));
1772 if (!pImage)
1773 rc = VERR_NO_MEMORY;
1774 else
1775 {
1776 pImage->pszFilename = pszFilename;
1777 pImage->pStorage = NULL;
1778 pImage->pVDIfsDisk = pVDIfsDisk;
1779 pImage->pVDIfsImage = pVDIfsImage;
1780
1781 rc = vhdxOpenImage(pImage, uOpenFlags);
1782 if (RT_SUCCESS(rc))
1783 *ppBackendData = pImage;
1784 else
1785 RTMemFree(pImage);
1786 }
1787 }
1788
1789 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
1790 return rc;
1791}
1792
1793/** @copydoc VBOXHDDBACKEND::pfnRename */
1794static int vhdxRename(void *pBackendData, const char *pszFilename)
1795{
1796 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
1797 int rc = VINF_SUCCESS;
1798 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1799
1800 /* Check arguments. */
1801 if ( !pImage
1802 || !pszFilename
1803 || !*pszFilename)
1804 rc = VERR_INVALID_PARAMETER;
1805 else
1806 {
1807 /* Close the image. */
1808 rc = vhdxFreeImage(pImage, false);
1809 if (RT_SUCCESS(rc))
1810 {
1811 /* Rename the file. */
1812 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
1813 if (RT_FAILURE(rc))
1814 {
1815 /* The move failed, try to reopen the original image. */
1816 int rc2 = vhdxOpenImage(pImage, pImage->uOpenFlags);
1817 if (RT_FAILURE(rc2))
1818 rc = rc2;
1819 }
1820 else
1821 {
1822 /* Update pImage with the new information. */
1823 pImage->pszFilename = pszFilename;
1824
1825 /* Open the old image with new name. */
1826 rc = vhdxOpenImage(pImage, pImage->uOpenFlags);
1827 }
1828 }
1829 }
1830
1831 LogFlowFunc(("returns %Rrc\n", rc));
1832 return rc;
1833}
1834
1835/** @copydoc VBOXHDDBACKEND::pfnClose */
1836static int vhdxClose(void *pBackendData, bool fDelete)
1837{
1838 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
1839 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1840 int rc;
1841
1842 rc = vhdxFreeImage(pImage, fDelete);
1843 RTMemFree(pImage);
1844
1845 LogFlowFunc(("returns %Rrc\n", rc));
1846 return rc;
1847}
1848
1849/** @copydoc VBOXHDDBACKEND::pfnRead */
1850static int vhdxRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
1851 size_t cbToRead, size_t *pcbActuallyRead)
1852{
1853 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
1854 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1855 int rc = VINF_SUCCESS;
1856
1857 AssertPtr(pImage);
1858 Assert(uOffset % 512 == 0);
1859 Assert(cbToRead % 512 == 0);
1860
1861 if ( uOffset + cbToRead > pImage->cbSize
1862 || cbToRead == 0)
1863 rc = VERR_INVALID_PARAMETER;
1864 else
1865 {
1866 uint32_t idxBat = uOffset / pImage->cbBlock;
1867 uint32_t offRead = uOffset % pImage->cbBlock;
1868 uint64_t uBatEntry;
1869
1870 idxBat += idxBat / pImage->uChunkRatio; /* Add interleaving sector bitmap entries. */
1871 uBatEntry = pImage->paBat[idxBat].u64BatEntry;
1872
1873 cbToRead = RT_MIN(cbToRead, pImage->cbBlock - offRead);
1874
1875 switch (VHDX_BAT_ENTRY_GET_STATE(uBatEntry))
1876 {
1877 case VHDX_BAT_ENTRY_PAYLOAD_BLOCK_NOT_PRESENT:
1878 case VHDX_BAT_ENTRY_PAYLOAD_BLOCK_UNDEFINED:
1879 case VHDX_BAT_ENTRY_PAYLOAD_BLOCK_ZERO:
1880 case VHDX_BAT_ENTRY_PAYLOAD_BLOCK_UNMAPPED:
1881 {
1882 memset(pvBuf, 0, cbToRead);
1883 break;
1884 }
1885 case VHDX_BAT_ENTRY_PAYLOAD_BLOCK_FULLY_PRESENT:
1886 {
1887 uint64_t offFile = VHDX_BAT_ENTRY_GET_FILE_OFFSET(uBatEntry) + offRead;
1888 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, offFile,
1889 pvBuf, cbToRead, NULL);
1890 break;
1891 }
1892 case VHDX_BAT_ENTRY_PAYLOAD_BLOCK_PARTIALLY_PRESENT:
1893 default:
1894 rc = VERR_INVALID_PARAMETER;
1895 break;
1896 }
1897
1898 if (pcbActuallyRead)
1899 *pcbActuallyRead = cbToRead;
1900 }
1901
1902 LogFlowFunc(("returns %Rrc\n", rc));
1903 return rc;
1904}
1905
1906/** @copydoc VBOXHDDBACKEND::pfnWrite */
1907static int vhdxWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
1908 size_t cbToWrite, size_t *pcbWriteProcess,
1909 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
1910{
1911 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
1912 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
1913 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1914 int rc;
1915
1916 AssertPtr(pImage);
1917 Assert(uOffset % 512 == 0);
1918 Assert(cbToWrite % 512 == 0);
1919
1920 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1921 rc = VERR_VD_IMAGE_READ_ONLY;
1922 else if ( uOffset + cbToWrite > pImage->cbSize
1923 || cbToWrite == 0)
1924 rc = VERR_INVALID_PARAMETER;
1925 else
1926 rc = VERR_NOT_SUPPORTED;
1927
1928 LogFlowFunc(("returns %Rrc\n", rc));
1929 return rc;
1930}
1931
1932/** @copydoc VBOXHDDBACKEND::pfnFlush */
1933static int vhdxFlush(void *pBackendData)
1934{
1935 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1936 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1937 int rc;
1938
1939 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1940 rc = VERR_VD_IMAGE_READ_ONLY;
1941 else
1942 rc = VERR_NOT_SUPPORTED;
1943
1944 LogFlowFunc(("returns %Rrc\n", rc));
1945 return rc;
1946}
1947
1948/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
1949static unsigned vhdxGetVersion(void *pBackendData)
1950{
1951 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1952 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1953
1954 AssertPtr(pImage);
1955
1956 if (pImage)
1957 return pImage->uVersion;
1958 else
1959 return 0;
1960}
1961
1962/** @copydoc VBOXHDDBACKEND::pfnGetSize */
1963static uint64_t vhdxGetSize(void *pBackendData)
1964{
1965 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1966 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1967 uint64_t cb = 0;
1968
1969 AssertPtr(pImage);
1970
1971 if (pImage && pImage->pStorage)
1972 cb = pImage->cbSize;
1973
1974 LogFlowFunc(("returns %llu\n", cb));
1975 return cb;
1976}
1977
1978/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
1979static uint64_t vhdxGetFileSize(void *pBackendData)
1980{
1981 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1982 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
1983 uint64_t cb = 0;
1984
1985 AssertPtr(pImage);
1986
1987 if (pImage)
1988 {
1989 uint64_t cbFile;
1990 if (pImage->pStorage)
1991 {
1992 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
1993 if (RT_SUCCESS(rc))
1994 cb = cbFile;
1995 }
1996 }
1997
1998 LogFlowFunc(("returns %lld\n", cb));
1999 return cb;
2000}
2001
2002/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
2003static int vhdxGetPCHSGeometry(void *pBackendData,
2004 PVDGEOMETRY pPCHSGeometry)
2005{
2006 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
2007 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2008 int rc;
2009
2010 AssertPtr(pImage);
2011
2012 if (pImage)
2013 {
2014 if (pImage->PCHSGeometry.cCylinders)
2015 {
2016 *pPCHSGeometry = pImage->PCHSGeometry;
2017 rc = VINF_SUCCESS;
2018 }
2019 else
2020 rc = VERR_VD_GEOMETRY_NOT_SET;
2021 }
2022 else
2023 rc = VERR_VD_NOT_OPENED;
2024
2025 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
2026 return rc;
2027}
2028
2029/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
2030static int vhdxSetPCHSGeometry(void *pBackendData,
2031 PCVDGEOMETRY pPCHSGeometry)
2032{
2033 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
2034 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2035 int rc = VINF_SUCCESS;
2036
2037 AssertPtr(pImage);
2038
2039 if (pImage)
2040 {
2041 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2042 rc = VERR_VD_IMAGE_READ_ONLY;
2043 else
2044 pImage->PCHSGeometry = *pPCHSGeometry;
2045 }
2046 else
2047 rc = VERR_VD_NOT_OPENED;
2048
2049out:
2050 LogFlowFunc(("returns %Rrc\n", rc));
2051 return rc;
2052}
2053
2054/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
2055static int vhdxGetLCHSGeometry(void *pBackendData,
2056 PVDGEOMETRY pLCHSGeometry)
2057{
2058 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
2059 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2060 int rc = VINF_SUCCESS;
2061
2062 AssertPtr(pImage);
2063
2064 if (pImage)
2065 {
2066 if (pImage->LCHSGeometry.cCylinders)
2067 *pLCHSGeometry = pImage->LCHSGeometry;
2068 else
2069 rc = VERR_VD_GEOMETRY_NOT_SET;
2070 }
2071 else
2072 rc = VERR_VD_NOT_OPENED;
2073
2074 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
2075 return rc;
2076}
2077
2078/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
2079static int vhdxSetLCHSGeometry(void *pBackendData,
2080 PCVDGEOMETRY pLCHSGeometry)
2081{
2082 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
2083 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2084 int rc = VINF_SUCCESS;
2085
2086 AssertPtr(pImage);
2087
2088 if (pImage)
2089 {
2090 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2091 rc = VERR_VD_IMAGE_READ_ONLY;
2092 else
2093 pImage->LCHSGeometry = *pLCHSGeometry;
2094 }
2095 else
2096 rc = VERR_VD_NOT_OPENED;
2097
2098 LogFlowFunc(("returns %Rrc\n", rc));
2099 return rc;
2100}
2101
2102/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
2103static unsigned vhdxGetImageFlags(void *pBackendData)
2104{
2105 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
2106 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2107 unsigned uImageFlags;
2108
2109 AssertPtr(pImage);
2110
2111 if (pImage)
2112 uImageFlags = pImage->uImageFlags;
2113 else
2114 uImageFlags = 0;
2115
2116 LogFlowFunc(("returns %#x\n", uImageFlags));
2117 return uImageFlags;
2118}
2119
2120/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
2121static unsigned vhdxGetOpenFlags(void *pBackendData)
2122{
2123 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
2124 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2125 unsigned uOpenFlags;
2126
2127 AssertPtr(pImage);
2128
2129 if (pImage)
2130 uOpenFlags = pImage->uOpenFlags;
2131 else
2132 uOpenFlags = 0;
2133
2134 LogFlowFunc(("returns %#x\n", uOpenFlags));
2135 return uOpenFlags;
2136}
2137
2138/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
2139static int vhdxSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
2140{
2141 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
2142 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2143 int rc = VINF_SUCCESS;
2144
2145 /* Image must be opened and the new flags must be valid. */
2146 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
2147 rc = VERR_INVALID_PARAMETER;
2148 else
2149 {
2150 /* Implement this operation via reopening the image. */
2151 rc = vhdxFreeImage(pImage, false);
2152 if (RT_SUCCESS(rc))
2153 rc = vhdxOpenImage(pImage, uOpenFlags);
2154 }
2155
2156 LogFlowFunc(("returns %Rrc\n", rc));
2157 return rc;
2158}
2159
2160/** @copydoc VBOXHDDBACKEND::pfnGetComment */
2161static int vhdxGetComment(void *pBackendData, char *pszComment,
2162 size_t cbComment)
2163{
2164 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
2165 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2166 int rc;
2167
2168 AssertPtr(pImage);
2169
2170 if (pImage)
2171 rc = VERR_NOT_SUPPORTED;
2172 else
2173 rc = VERR_VD_NOT_OPENED;
2174
2175 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
2176 return rc;
2177}
2178
2179/** @copydoc VBOXHDDBACKEND::pfnSetComment */
2180static int vhdxSetComment(void *pBackendData, const char *pszComment)
2181{
2182 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
2183 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2184 int rc;
2185
2186 AssertPtr(pImage);
2187
2188 if (pImage)
2189 {
2190 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2191 rc = VERR_VD_IMAGE_READ_ONLY;
2192 else
2193 rc = VERR_NOT_SUPPORTED;
2194 }
2195 else
2196 rc = VERR_VD_NOT_OPENED;
2197
2198 LogFlowFunc(("returns %Rrc\n", rc));
2199 return rc;
2200}
2201
2202/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
2203static int vhdxGetUuid(void *pBackendData, PRTUUID pUuid)
2204{
2205 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
2206 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2207 int rc;
2208
2209 AssertPtr(pImage);
2210
2211 if (pImage)
2212 rc = VERR_NOT_SUPPORTED;
2213 else
2214 rc = VERR_VD_NOT_OPENED;
2215
2216 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
2217 return rc;
2218}
2219
2220/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
2221static int vhdxSetUuid(void *pBackendData, PCRTUUID pUuid)
2222{
2223 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
2224 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2225 int rc;
2226
2227 LogFlowFunc(("%RTuuid\n", pUuid));
2228 AssertPtr(pImage);
2229
2230 if (pImage)
2231 {
2232 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2233 rc = VERR_NOT_SUPPORTED;
2234 else
2235 rc = VERR_VD_IMAGE_READ_ONLY;
2236 }
2237 else
2238 rc = VERR_VD_NOT_OPENED;
2239
2240 LogFlowFunc(("returns %Rrc\n", rc));
2241 return rc;
2242}
2243
2244/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
2245static int vhdxGetModificationUuid(void *pBackendData, PRTUUID pUuid)
2246{
2247 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
2248 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2249 int rc;
2250
2251 AssertPtr(pImage);
2252
2253 if (pImage)
2254 rc = VERR_NOT_SUPPORTED;
2255 else
2256 rc = VERR_VD_NOT_OPENED;
2257
2258 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
2259 return rc;
2260}
2261
2262/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
2263static int vhdxSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
2264{
2265 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
2266 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2267 int rc;
2268
2269 AssertPtr(pImage);
2270
2271 if (pImage)
2272 {
2273 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2274 rc = VERR_NOT_SUPPORTED;
2275 else
2276 rc = VERR_VD_IMAGE_READ_ONLY;
2277 }
2278 else
2279 rc = VERR_VD_NOT_OPENED;
2280
2281 LogFlowFunc(("returns %Rrc\n", rc));
2282 return rc;
2283}
2284
2285/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
2286static int vhdxGetParentUuid(void *pBackendData, PRTUUID pUuid)
2287{
2288 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
2289 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2290 int rc;
2291
2292 AssertPtr(pImage);
2293
2294 if (pImage)
2295 rc = VERR_NOT_SUPPORTED;
2296 else
2297 rc = VERR_VD_NOT_OPENED;
2298
2299 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
2300 return rc;
2301}
2302
2303/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
2304static int vhdxSetParentUuid(void *pBackendData, PCRTUUID pUuid)
2305{
2306 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
2307 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2308 int rc;
2309
2310 AssertPtr(pImage);
2311
2312 if (pImage)
2313 {
2314 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2315 rc = VERR_NOT_SUPPORTED;
2316 else
2317 rc = VERR_VD_IMAGE_READ_ONLY;
2318 }
2319 else
2320 rc = VERR_VD_NOT_OPENED;
2321
2322 LogFlowFunc(("returns %Rrc\n", rc));
2323 return rc;
2324}
2325
2326/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
2327static int vhdxGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
2328{
2329 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
2330 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2331 int rc;
2332
2333 AssertPtr(pImage);
2334
2335 if (pImage)
2336 rc = VERR_NOT_SUPPORTED;
2337 else
2338 rc = VERR_VD_NOT_OPENED;
2339
2340 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
2341 return rc;
2342}
2343
2344/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
2345static int vhdxSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
2346{
2347 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
2348 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2349 int rc;
2350
2351 AssertPtr(pImage);
2352
2353 if (pImage)
2354 {
2355 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2356 rc = VERR_NOT_SUPPORTED;
2357 else
2358 rc = VERR_VD_IMAGE_READ_ONLY;
2359 }
2360 else
2361 rc = VERR_VD_NOT_OPENED;
2362
2363 LogFlowFunc(("returns %Rrc\n", rc));
2364 return rc;
2365}
2366
2367/** @copydoc VBOXHDDBACKEND::pfnDump */
2368static void vhdxDump(void *pBackendData)
2369{
2370 PVHDXIMAGE pImage = (PVHDXIMAGE)pBackendData;
2371
2372 AssertPtr(pImage);
2373 if (pImage)
2374 {
2375 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
2376 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
2377 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
2378 pImage->cbSize / 512);
2379 }
2380}
2381
2382
2383VBOXHDDBACKEND g_VhdxBackend =
2384{
2385 /* pszBackendName */
2386 "VHDX",
2387 /* cbSize */
2388 sizeof(VBOXHDDBACKEND),
2389 /* uBackendCaps */
2390 VD_CAP_FILE | VD_CAP_VFS,
2391 /* paFileExtensions */
2392 s_aVhdxFileExtensions,
2393 /* paConfigInfo */
2394 NULL,
2395 /* hPlugin */
2396 NIL_RTLDRMOD,
2397 /* pfnCheckIfValid */
2398 vhdxCheckIfValid,
2399 /* pfnOpen */
2400 vhdxOpen,
2401 /* pfnCreate */
2402 NULL,
2403 /* pfnRename */
2404 vhdxRename,
2405 /* pfnClose */
2406 vhdxClose,
2407 /* pfnRead */
2408 vhdxRead,
2409 /* pfnWrite */
2410 vhdxWrite,
2411 /* pfnFlush */
2412 vhdxFlush,
2413 /* pfnGetVersion */
2414 vhdxGetVersion,
2415 /* pfnGetSize */
2416 vhdxGetSize,
2417 /* pfnGetFileSize */
2418 vhdxGetFileSize,
2419 /* pfnGetPCHSGeometry */
2420 vhdxGetPCHSGeometry,
2421 /* pfnSetPCHSGeometry */
2422 vhdxSetPCHSGeometry,
2423 /* pfnGetLCHSGeometry */
2424 vhdxGetLCHSGeometry,
2425 /* pfnSetLCHSGeometry */
2426 vhdxSetLCHSGeometry,
2427 /* pfnGetImageFlags */
2428 vhdxGetImageFlags,
2429 /* pfnGetOpenFlags */
2430 vhdxGetOpenFlags,
2431 /* pfnSetOpenFlags */
2432 vhdxSetOpenFlags,
2433 /* pfnGetComment */
2434 vhdxGetComment,
2435 /* pfnSetComment */
2436 vhdxSetComment,
2437 /* pfnGetUuid */
2438 vhdxGetUuid,
2439 /* pfnSetUuid */
2440 vhdxSetUuid,
2441 /* pfnGetModificationUuid */
2442 vhdxGetModificationUuid,
2443 /* pfnSetModificationUuid */
2444 vhdxSetModificationUuid,
2445 /* pfnGetParentUuid */
2446 vhdxGetParentUuid,
2447 /* pfnSetParentUuid */
2448 vhdxSetParentUuid,
2449 /* pfnGetParentModificationUuid */
2450 vhdxGetParentModificationUuid,
2451 /* pfnSetParentModificationUuid */
2452 vhdxSetParentModificationUuid,
2453 /* pfnDump */
2454 vhdxDump,
2455 /* pfnGetTimeStamp */
2456 NULL,
2457 /* pfnGetParentTimeStamp */
2458 NULL,
2459 /* pfnSetParentTimeStamp */
2460 NULL,
2461 /* pfnGetParentFilename */
2462 NULL,
2463 /* pfnSetParentFilename */
2464 NULL,
2465 /* pfnAsyncRead */
2466 NULL,
2467 /* pfnAsyncWrite */
2468 NULL,
2469 /* pfnAsyncFlush */
2470 NULL,
2471 /* pfnComposeLocation */
2472 genericFileComposeLocation,
2473 /* pfnComposeName */
2474 genericFileComposeName,
2475 /* pfnCompact */
2476 NULL,
2477 /* pfnResize */
2478 NULL,
2479 /* pfnDiscard */
2480 NULL,
2481 /* pfnAsyncDiscard */
2482 NULL,
2483 /* pfnRepair */
2484 NULL
2485};
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