VirtualBox

source: vbox/trunk/src/VBox/Storage/VDICore.h@ 93912

Last change on this file since 93912 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.9 KB
Line 
1/* $Id: VDICore.h 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * Virtual Disk Image (VDI), Core Code Header (internal).
4 */
5
6/*
7 * Copyright (C) 2006-2022 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#ifndef VBOX_INCLUDED_SRC_Storage_VDICore_h
19#define VBOX_INCLUDED_SRC_Storage_VDICore_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24
25/*******************************************************************************
26* Header Files *
27*******************************************************************************/
28#include <VBox/vd.h>
29#include <VBox/err.h>
30
31#include <VBox/log.h>
32#include <iprt/alloc.h>
33#include <iprt/assert.h>
34#include <iprt/uuid.h>
35#include <iprt/string.h>
36#include <iprt/asm.h>
37
38
39/*******************************************************************************
40* Constants And Macros, Structures and Typedefs *
41*******************************************************************************/
42
43/** Image info, not handled anyhow.
44 * Must be less than 64 bytes in length, including the trailing 0.
45 */
46#define VDI_IMAGE_FILE_INFO "<<< Oracle VM VirtualBox Disk Image >>>\n"
47
48/** The Sector size.
49 * Currently we support only 512 bytes sectors.
50 */
51#define VDI_GEOMETRY_SECTOR_SIZE (512)
52/** 512 = 2^^9 */
53#define VDI_GEOMETRY_SECTOR_SHIFT (9)
54
55/**
56 * Harddisk geometry.
57 */
58#pragma pack(1)
59typedef struct VDIDISKGEOMETRY
60{
61 /** Cylinders. */
62 uint32_t cCylinders;
63 /** Heads. */
64 uint32_t cHeads;
65 /** Sectors per track. */
66 uint32_t cSectors;
67 /** Sector size. (bytes per sector) */
68 uint32_t cbSector;
69} VDIDISKGEOMETRY, *PVDIDISKGEOMETRY;
70#pragma pack()
71
72/** Image signature. */
73#define VDI_IMAGE_SIGNATURE (0xbeda107f)
74
75/**
76 * Pre-Header to be stored in image file - used for version control.
77 */
78#pragma pack(1)
79typedef struct VDIPREHEADER
80{
81 /** Just text info about image type, for eyes only. */
82 char szFileInfo[64];
83 /** The image signature (VDI_IMAGE_SIGNATURE). */
84 uint32_t u32Signature;
85 /** The image version (VDI_IMAGE_VERSION). */
86 uint32_t u32Version;
87} VDIPREHEADER, *PVDIPREHEADER;
88#pragma pack()
89
90/**
91 * Size of szComment field of HDD image header.
92 */
93#define VDI_IMAGE_COMMENT_SIZE 256
94
95/**
96 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 0.
97 * Prepended by VDIPREHEADER.
98 */
99#pragma pack(1)
100typedef struct VDIHEADER0
101{
102 /** The image type (VDI_IMAGE_TYPE_*). */
103 uint32_t u32Type;
104 /** Image flags (VDI_IMAGE_FLAGS_*). */
105 uint32_t fFlags;
106 /** Image comment. (UTF-8) */
107 char szComment[VDI_IMAGE_COMMENT_SIZE];
108 /** Legacy image geometry (previous code stored PCHS there). */
109 VDIDISKGEOMETRY LegacyGeometry;
110 /** Size of disk (in bytes). */
111 uint64_t cbDisk;
112 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) */
113 uint32_t cbBlock;
114 /** Number of blocks. */
115 uint32_t cBlocks;
116 /** Number of allocated blocks. */
117 uint32_t cBlocksAllocated;
118 /** UUID of image. */
119 RTUUID uuidCreate;
120 /** UUID of image's last modification. */
121 RTUUID uuidModify;
122 /** Only for secondary images - UUID of primary image. */
123 RTUUID uuidLinkage;
124} VDIHEADER0, *PVDIHEADER0;
125#pragma pack()
126
127/**
128 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 1,
129 * VDI_IMAGE_VERSION_MINOR = 1. Prepended by VDIPREHEADER.
130 */
131#pragma pack(1)
132typedef struct VDIHEADER1
133{
134 /** Size of this structure in bytes. */
135 uint32_t cbHeader;
136 /** The image type (VDI_IMAGE_TYPE_*). */
137 uint32_t u32Type;
138 /** Image flags (VDI_IMAGE_FLAGS_*). */
139 uint32_t fFlags;
140 /** Image comment. (UTF-8) */
141 char szComment[VDI_IMAGE_COMMENT_SIZE];
142 /** Offset of Blocks array from the beginning of image file.
143 * Should be sector-aligned for HDD access optimization. */
144 uint32_t offBlocks;
145 /** Offset of image data from the beginning of image file.
146 * Should be sector-aligned for HDD access optimization. */
147 uint32_t offData;
148 /** Legacy image geometry (previous code stored PCHS there). */
149 VDIDISKGEOMETRY LegacyGeometry;
150 /** Was BIOS HDD translation mode, now unused. */
151 uint32_t u32Dummy;
152 /** Size of disk (in bytes). */
153 uint64_t cbDisk;
154 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) Should be a power of 2! */
155 uint32_t cbBlock;
156 /** Size of additional service information of every data block.
157 * Prepended before block data. May be 0.
158 * Should be a power of 2 and sector-aligned for optimization reasons. */
159 uint32_t cbBlockExtra;
160 /** Number of blocks. */
161 uint32_t cBlocks;
162 /** Number of allocated blocks. */
163 uint32_t cBlocksAllocated;
164 /** UUID of image. */
165 RTUUID uuidCreate;
166 /** UUID of image's last modification. */
167 RTUUID uuidModify;
168 /** Only for secondary images - UUID of previous image. */
169 RTUUID uuidLinkage;
170 /** Only for secondary images - UUID of previous image's last modification. */
171 RTUUID uuidParentModify;
172} VDIHEADER1, *PVDIHEADER1;
173#pragma pack()
174
175/**
176 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 1,
177 * VDI_IMAGE_VERSION_MINOR = 1, the slightly changed variant necessary as the
178 * old released code doesn't support changing the minor version at all.
179 */
180#pragma pack(1)
181typedef struct VDIHEADER1PLUS
182{
183 /** Size of this structure in bytes. */
184 uint32_t cbHeader;
185 /** The image type (VDI_IMAGE_TYPE_*). */
186 uint32_t u32Type;
187 /** Image flags (VDI_IMAGE_FLAGS_*). */
188 uint32_t fFlags;
189 /** Image comment. (UTF-8) */
190 char szComment[VDI_IMAGE_COMMENT_SIZE];
191 /** Offset of blocks array from the beginning of image file.
192 * Should be sector-aligned for HDD access optimization. */
193 uint32_t offBlocks;
194 /** Offset of image data from the beginning of image file.
195 * Should be sector-aligned for HDD access optimization. */
196 uint32_t offData;
197 /** Legacy image geometry (previous code stored PCHS there). */
198 VDIDISKGEOMETRY LegacyGeometry;
199 /** Was BIOS HDD translation mode, now unused. */
200 uint32_t u32Dummy;
201 /** Size of disk (in bytes). */
202 uint64_t cbDisk;
203 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) Should be a power of 2! */
204 uint32_t cbBlock;
205 /** Size of additional service information of every data block.
206 * Prepended before block data. May be 0.
207 * Should be a power of 2 and sector-aligned for optimization reasons. */
208 uint32_t cbBlockExtra;
209 /** Number of blocks. */
210 uint32_t cBlocks;
211 /** Number of allocated blocks. */
212 uint32_t cBlocksAllocated;
213 /** UUID of image. */
214 RTUUID uuidCreate;
215 /** UUID of image's last modification. */
216 RTUUID uuidModify;
217 /** Only for secondary images - UUID of previous image. */
218 RTUUID uuidLinkage;
219 /** Only for secondary images - UUID of previous image's last modification. */
220 RTUUID uuidParentModify;
221 /** LCHS image geometry (new field in VDI1.2 version. */
222 VDIDISKGEOMETRY LCHSGeometry;
223} VDIHEADER1PLUS, *PVDIHEADER1PLUS;
224#pragma pack()
225
226/**
227 * Header structure for all versions.
228 */
229typedef struct VDIHEADER
230{
231 unsigned uVersion;
232 union
233 {
234 VDIHEADER0 v0;
235 VDIHEADER1 v1;
236 VDIHEADER1PLUS v1plus;
237 } u;
238} VDIHEADER, *PVDIHEADER;
239
240/**
241 * File alignment boundary for both the block array and data area. Should be
242 * at least the size of a physical sector on disk for performance reasons.
243 * Bumped to 1MB because SSDs tend to have 8kb per page so we don't have to worry
244 * about proper alignment in the near future again. */
245#define VDI_DATA_ALIGN _1M
246
247/** Block 'pointer'. */
248typedef uint32_t VDIIMAGEBLOCKPOINTER;
249/** Pointer to a block 'pointer'. */
250typedef VDIIMAGEBLOCKPOINTER *PVDIIMAGEBLOCKPOINTER;
251
252/**
253 * Block marked as free is not allocated in image file, read from this
254 * block may returns any random data.
255 */
256#define VDI_IMAGE_BLOCK_FREE ((VDIIMAGEBLOCKPOINTER)~0)
257
258/**
259 * Block marked as zero is not allocated in image file, read from this
260 * block returns zeroes.
261 */
262#define VDI_IMAGE_BLOCK_ZERO ((VDIIMAGEBLOCKPOINTER)~1)
263
264/**
265 * Block 'pointer' >= VDI_IMAGE_BLOCK_UNALLOCATED indicates block is not
266 * allocated in image file.
267 */
268#define VDI_IMAGE_BLOCK_UNALLOCATED (VDI_IMAGE_BLOCK_ZERO)
269#define IS_VDI_IMAGE_BLOCK_ALLOCATED(bp) (bp < VDI_IMAGE_BLOCK_UNALLOCATED)
270
271#define GET_MAJOR_HEADER_VERSION(ph) (VDI_GET_VERSION_MAJOR((ph)->uVersion))
272#define GET_MINOR_HEADER_VERSION(ph) (VDI_GET_VERSION_MINOR((ph)->uVersion))
273
274/** @name VDI image types
275 * @{ */
276typedef enum VDIIMAGETYPE
277{
278 /** Normal dynamically growing base image file. */
279 VDI_IMAGE_TYPE_NORMAL = 1,
280 /** Preallocated base image file of a fixed size. */
281 VDI_IMAGE_TYPE_FIXED,
282 /** Dynamically growing image file for undo/commit changes support. */
283 VDI_IMAGE_TYPE_UNDO,
284 /** Dynamically growing image file for differencing support. */
285 VDI_IMAGE_TYPE_DIFF,
286
287 /** First valid image type value. */
288 VDI_IMAGE_TYPE_FIRST = VDI_IMAGE_TYPE_NORMAL,
289 /** Last valid image type value. */
290 VDI_IMAGE_TYPE_LAST = VDI_IMAGE_TYPE_DIFF
291} VDIIMAGETYPE;
292/** Pointer to VDI image type. */
293typedef VDIIMAGETYPE *PVDIIMAGETYPE;
294/** @} */
295
296/*******************************************************************************
297* Internal Functions for header access *
298*******************************************************************************/
299DECLINLINE(VDIIMAGETYPE) getImageType(PVDIHEADER ph)
300{
301 switch (GET_MAJOR_HEADER_VERSION(ph))
302 {
303 case 0: return (VDIIMAGETYPE)ph->u.v0.u32Type;
304 case 1: return (VDIIMAGETYPE)ph->u.v1.u32Type;
305 }
306 AssertFailed();
307 return (VDIIMAGETYPE)0;
308}
309
310DECLINLINE(unsigned) getImageFlags(PVDIHEADER ph)
311{
312 switch (GET_MAJOR_HEADER_VERSION(ph))
313 {
314 case 0:
315 /* VDI image flag conversion to VD image flags. */
316 return ph->u.v0.fFlags << 8;
317 case 1:
318 /* VDI image flag conversion to VD image flags. */
319 return ph->u.v1.fFlags << 8;
320 }
321 AssertFailed();
322 return 0;
323}
324
325DECLINLINE(char *) getImageComment(PVDIHEADER ph)
326{
327 switch (GET_MAJOR_HEADER_VERSION(ph))
328 {
329 case 0: return &ph->u.v0.szComment[0];
330 case 1: return &ph->u.v1.szComment[0];
331 }
332 AssertFailed();
333 return NULL;
334}
335
336DECLINLINE(unsigned) getImageBlocksOffset(PVDIHEADER ph)
337{
338 switch (GET_MAJOR_HEADER_VERSION(ph))
339 {
340 case 0: return (sizeof(VDIPREHEADER) + sizeof(VDIHEADER0));
341 case 1: return ph->u.v1.offBlocks;
342 }
343 AssertFailed();
344 return 0;
345}
346
347DECLINLINE(uint32_t) getImageDataOffset(PVDIHEADER ph)
348{
349 switch (GET_MAJOR_HEADER_VERSION(ph))
350 {
351 case 0: return sizeof(VDIPREHEADER) + sizeof(VDIHEADER0) + \
352 (ph->u.v0.cBlocks * sizeof(VDIIMAGEBLOCKPOINTER));
353 case 1: return ph->u.v1.offData;
354 }
355 AssertFailed();
356 return 0;
357}
358
359DECLINLINE(void) setImageDataOffset(PVDIHEADER ph, uint32_t offData)
360{
361 switch (GET_MAJOR_HEADER_VERSION(ph))
362 {
363 case 0: return;
364 case 1: ph->u.v1.offData = offData; return;
365 }
366 AssertFailed();
367}
368
369DECLINLINE(PVDIDISKGEOMETRY) getImageLCHSGeometry(PVDIHEADER ph)
370{
371 switch (GET_MAJOR_HEADER_VERSION(ph))
372 {
373 case 0: return NULL;
374 case 1:
375 switch (GET_MINOR_HEADER_VERSION(ph))
376 {
377 case 1:
378 if (ph->u.v1.cbHeader < sizeof(ph->u.v1plus))
379 return NULL;
380 else
381 return &ph->u.v1plus.LCHSGeometry;
382 }
383 }
384 AssertFailed();
385 return NULL;
386}
387
388DECLINLINE(uint64_t) getImageDiskSize(PVDIHEADER ph)
389{
390 switch (GET_MAJOR_HEADER_VERSION(ph))
391 {
392 case 0: return ph->u.v0.cbDisk;
393 case 1: return ph->u.v1.cbDisk;
394 }
395 AssertFailed();
396 return 0;
397}
398
399DECLINLINE(void) setImageDiskSize(PVDIHEADER ph, uint64_t cbDisk)
400{
401 switch (GET_MAJOR_HEADER_VERSION(ph))
402 {
403 case 0: ph->u.v0.cbDisk = cbDisk; return;
404 case 1: ph->u.v1.cbDisk = cbDisk; return;
405 }
406 AssertFailed();
407}
408
409DECLINLINE(unsigned) getImageBlockSize(PVDIHEADER ph)
410{
411 switch (GET_MAJOR_HEADER_VERSION(ph))
412 {
413 case 0: return ph->u.v0.cbBlock;
414 case 1: return ph->u.v1.cbBlock;
415 }
416 AssertFailed();
417 return 0;
418}
419
420DECLINLINE(unsigned) getImageExtraBlockSize(PVDIHEADER ph)
421{
422 switch (GET_MAJOR_HEADER_VERSION(ph))
423 {
424 case 0: return 0;
425 case 1: return ph->u.v1.cbBlockExtra;
426 }
427 AssertFailed();
428 return 0;
429}
430
431DECLINLINE(unsigned) getImageBlocks(PVDIHEADER ph)
432{
433 switch (GET_MAJOR_HEADER_VERSION(ph))
434 {
435 case 0: return ph->u.v0.cBlocks;
436 case 1: return ph->u.v1.cBlocks;
437 }
438 AssertFailed();
439 return 0;
440}
441
442DECLINLINE(void) setImageBlocks(PVDIHEADER ph, unsigned cBlocks)
443{
444 switch (GET_MAJOR_HEADER_VERSION(ph))
445 {
446 case 0: ph->u.v0.cBlocks = cBlocks; return;
447 case 1: ph->u.v1.cBlocks = cBlocks; return;
448 }
449 AssertFailed();
450}
451
452
453DECLINLINE(unsigned) getImageBlocksAllocated(PVDIHEADER ph)
454{
455 switch (GET_MAJOR_HEADER_VERSION(ph))
456 {
457 case 0: return ph->u.v0.cBlocksAllocated;
458 case 1: return ph->u.v1.cBlocksAllocated;
459 }
460 AssertFailed();
461 return 0;
462}
463
464DECLINLINE(void) setImageBlocksAllocated(PVDIHEADER ph, unsigned cBlocks)
465{
466 switch (GET_MAJOR_HEADER_VERSION(ph))
467 {
468 case 0: ph->u.v0.cBlocksAllocated = cBlocks; return;
469 case 1: ph->u.v1.cBlocksAllocated = cBlocks; return;
470 }
471 AssertFailed();
472}
473
474#ifdef _MSC_VER
475# pragma warning(disable:4366) /* (harmless "misalignment") */
476#endif
477
478DECLINLINE(PRTUUID) getImageCreationUUID(PVDIHEADER ph)
479{
480 switch (GET_MAJOR_HEADER_VERSION(ph))
481 {
482 case 0: return &ph->u.v0.uuidCreate;
483 case 1: return &ph->u.v1.uuidCreate;
484 }
485 AssertFailed();
486 return NULL;
487}
488
489DECLINLINE(PRTUUID) getImageModificationUUID(PVDIHEADER ph)
490{
491 switch (GET_MAJOR_HEADER_VERSION(ph))
492 {
493 case 0: return &ph->u.v0.uuidModify;
494 case 1: return &ph->u.v1.uuidModify;
495 }
496 AssertFailed();
497 return NULL;
498}
499
500DECLINLINE(PRTUUID) getImageParentUUID(PVDIHEADER ph)
501{
502 switch (GET_MAJOR_HEADER_VERSION(ph))
503 {
504 case 0: return &ph->u.v0.uuidLinkage;
505 case 1: return &ph->u.v1.uuidLinkage;
506 }
507 AssertFailed();
508 return NULL;
509}
510
511DECLINLINE(PRTUUID) getImageParentModificationUUID(PVDIHEADER ph)
512{
513 switch (GET_MAJOR_HEADER_VERSION(ph))
514 {
515 case 1: return &ph->u.v1.uuidParentModify;
516 }
517 AssertFailed();
518 return NULL;
519}
520
521#ifdef _MSC_VER
522# pragma warning(default:4366)
523#endif
524
525/**
526 * Image structure
527 */
528typedef struct VDIIMAGEDESC
529{
530 /** Opaque storage handle. */
531 PVDIOSTORAGE pStorage;
532 /** Image open flags, VD_OPEN_FLAGS_*. */
533 unsigned uOpenFlags;
534 /** Image pre-header. */
535 VDIPREHEADER PreHeader;
536 /** Image header. */
537 VDIHEADER Header;
538 /** Pointer to a block array. */
539 PVDIIMAGEBLOCKPOINTER paBlocks;
540 /** Pointer to the block array for back resolving (used if discarding is enabled). */
541 unsigned *paBlocksRev;
542 /** fFlags copy from image header, for speed optimization. */
543 unsigned uImageFlags;
544 /** Start offset of block array in image file, here for speed optimization. */
545 unsigned offStartBlocks;
546 /** Start offset of data in image file, here for speed optimization. */
547 unsigned offStartData;
548 /** Block mask for getting the offset into a block from a byte hdd offset. */
549 unsigned uBlockMask;
550 /** Block shift value for converting byte hdd offset into paBlock index. */
551 unsigned uShiftOffset2Index;
552 /** Offset of data from the beginning of block. */
553 unsigned offStartBlockData;
554 /** Total size of image block (including the extra data). */
555 unsigned cbTotalBlockData;
556 /** Allocation Block Size */
557 unsigned cbAllocationBlock;
558 /** Container filename. (UTF-8) */
559 const char *pszFilename;
560 /** Physical geometry of this image (never actually stored). */
561 VDGEOMETRY PCHSGeometry;
562 /** Pointer to the per-disk VD interface list. */
563 PVDINTERFACE pVDIfsDisk;
564 /** Pointer to the per-image VD interface list. */
565 PVDINTERFACE pVDIfsImage;
566 /** Error interface. */
567 PVDINTERFACEERROR pIfError;
568 /** I/O interface. */
569 PVDINTERFACEIOINT pIfIo;
570 /** Current size of the image (used for range validation when reading). */
571 uint64_t cbImage;
572 /** The static region list. */
573 VDREGIONLIST RegionList;
574} VDIIMAGEDESC, *PVDIIMAGEDESC;
575
576/**
577 * Async block discard states.
578 */
579typedef enum VDIBLOCKDISCARDSTATE
580{
581 /** Invalid. */
582 VDIBLOCKDISCARDSTATE_INVALID = 0,
583 /** Read the last block. */
584 VDIBLOCKDISCARDSTATE_READ_BLOCK,
585 /** Write block into the hole. */
586 VDIBLOCKDISCARDSTATE_WRITE_BLOCK,
587 /** Update metadata. */
588 VDIBLOCKDISCARDSTATE_UPDATE_METADATA,
589 /** 32bit hack. */
590 VDIBLOCKDISCARDSTATE_32BIT_HACK = 0x7fffffff
591} VDIBLOCKDISCARDSTATE;
592
593/**
594 * Async block discard structure.
595 */
596typedef struct VDIBLOCKDISCARDASYNC
597{
598 /** State of the block discard. */
599 VDIBLOCKDISCARDSTATE enmState;
600 /** Pointer to the block data. */
601 void *pvBlock;
602 /** Block index in the block table. */
603 unsigned uBlock;
604 /** Block pointer to the block to discard. */
605 VDIIMAGEBLOCKPOINTER ptrBlockDiscard;
606 /** Index of the last block in the reverse block table. */
607 unsigned idxLastBlock;
608 /** Index of the last block in the block table (gathered from the reverse block table). */
609 unsigned uBlockLast;
610} VDIBLOCKDISCARDASYNC, *PVDIBLOCKDISCARDASYNC;
611
612/**
613 * Async image expansion state.
614 */
615typedef struct VDIASYNCBLOCKALLOC
616{
617 /** Number of blocks allocated. */
618 unsigned cBlocksAllocated;
619 /** Block index to allocate. */
620 unsigned uBlock;
621} VDIASYNCBLOCKALLOC, *PVDIASYNCBLOCKALLOC;
622
623/**
624 * Endianess conversion direction.
625 */
626typedef enum VDIECONV
627{
628 /** Host to file endianess. */
629 VDIECONV_H2F = 0,
630 /** File to host endianess. */
631 VDIECONV_F2H
632} VDIECONV;
633
634#endif /* !VBOX_INCLUDED_SRC_Storage_VDICore_h */
635
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