VirtualBox

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

Last change on this file since 106683 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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