VirtualBox

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

Last change on this file since 2392 was 2358, checked in by vboxsync, 18 years ago

New VMDK code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/** $Id: VDICore.h 2358 2007-04-26 16:53:00Z vboxsync $ */
2/** @file
3 * Virtual Disk Image (VDI), Core Code Header (internal).
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#ifndef __VDICore_h__
23
24
25/*******************************************************************************
26* Header Files *
27*******************************************************************************/
28#include <VBox/VBoxHDD.h>
29#include <VBox/pdm.h>
30#include <VBox/mm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/alloc.h>
35#include <iprt/assert.h>
36#include <iprt/uuid.h>
37#include <iprt/file.h>
38#include <iprt/string.h>
39#include <iprt/asm.h>
40
41
42/*******************************************************************************
43* Constants And Macros, Structures and Typedefs *
44*******************************************************************************/
45
46/** Image info, not handled anyhow.
47 * Must be less than 64 bytes in length, including the trailing 0.
48 */
49#define VDI_IMAGE_FILE_INFO "<<< InnoTek VirtualBox Disk Image >>>\n"
50
51/** The Sector size.
52 * Currently we support only 512 bytes sectors.
53 */
54#define VDI_GEOMETRY_SECTOR_SIZE (512)
55/** 512 = 2^^9 */
56#define VDI_GEOMETRY_SECTOR_SHIFT (9)
57
58/**
59 * Harddisk geometry.
60 */
61#pragma pack(1)
62typedef struct VDIDISKGEOMETRY
63{
64 /** Cylinders. */
65 uint32_t cCylinders;
66 /** Heads. */
67 uint32_t cHeads;
68 /** Sectors per track. */
69 uint32_t cSectors;
70 /** Sector size. (bytes per sector) */
71 uint32_t cbSector;
72} VDIDISKGEOMETRY, *PVDIDISKGEOMETRY;
73#pragma pack()
74
75/** Image signature. */
76#define VDI_IMAGE_SIGNATURE (0xbeda107f)
77
78/**
79 * Pre-Header to be stored in image file - used for version control.
80 */
81#pragma pack(1)
82typedef struct VDIPREHEADER
83{
84 /** Just text info about image type, for eyes only. */
85 char szFileInfo[64];
86 /** The image signature (VDI_IMAGE_SIGNATURE). */
87 uint32_t u32Signature;
88 /** The image version (VDI_IMAGE_VERSION). */
89 uint32_t u32Version;
90} VDIPREHEADER, *PVDIPREHEADER;
91#pragma pack()
92
93/**
94 * Size of szComment field of HDD image header.
95 */
96#define VDI_IMAGE_COMMENT_SIZE 256
97
98/**
99 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 0.
100 * Prepended by VDIPREHEADER.
101 */
102#pragma pack(1)
103typedef struct VDIHEADER0
104{
105 /** The image type (VDI_IMAGE_TYPE_*). */
106 uint32_t u32Type;
107 /** Image flags (VDI_IMAGE_FLAGS_*). */
108 uint32_t fFlags;
109 /** Image comment. (UTF-8) */
110 char szComment[VDI_IMAGE_COMMENT_SIZE];
111 /** Image geometry. */
112 VDIDISKGEOMETRY Geometry;
113 /** Size of disk (in bytes). */
114 uint64_t cbDisk;
115 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) */
116 uint32_t cbBlock;
117 /** Number of blocks. */
118 uint32_t cBlocks;
119 /** Number of allocated blocks. */
120 uint32_t cBlocksAllocated;
121 /** UUID of image. */
122 RTUUID uuidCreate;
123 /** UUID of image's last modification. */
124 RTUUID uuidModify;
125 /** Only for secondary images - UUID of primary image. */
126 RTUUID uuidLinkage;
127} VDIHEADER0, *PVDIHEADER0;
128#pragma pack()
129
130/**
131 * Header to be stored in image file, VDI_IMAGE_VERSION_MAJOR = 1.
132 * Prepended by VDIPREHEADER.
133 */
134#pragma pack(1)
135typedef struct VDIHEADER1
136{
137 /** Size of this structure in bytes. */
138 uint32_t cbHeader;
139 /** The image type (VDI_IMAGE_TYPE_*). */
140 uint32_t u32Type;
141 /** Image flags (VDI_IMAGE_FLAGS_*). */
142 uint32_t fFlags;
143 /** Image comment. (UTF-8) */
144 char szComment[VDI_IMAGE_COMMENT_SIZE];
145 /** Offset of Blocks array from the begining of image file.
146 * Should be sector-aligned for HDD access optimization. */
147 uint32_t offBlocks;
148 /** Offset of image data from the begining of image file.
149 * Should be sector-aligned for HDD access optimization. */
150 uint32_t offData;
151 /** Image geometry. */
152 VDIDISKGEOMETRY Geometry;
153 /** BIOS HDD translation mode, see PDMBIOSTRANSLATION. */
154 uint32_t u32Translation;
155 /** Size of disk (in bytes). */
156 uint64_t cbDisk;
157 /** Block size. (For instance VDI_IMAGE_BLOCK_SIZE.) Should be a power of 2! */
158 uint32_t cbBlock;
159 /** Size of additional service information of every data block.
160 * Prepended before block data. May be 0.
161 * Should be a power of 2 and sector-aligned for optimization reasons. */
162 uint32_t cbBlockExtra;
163 /** Number of blocks. */
164 uint32_t cBlocks;
165 /** Number of allocated blocks. */
166 uint32_t cBlocksAllocated;
167 /** UUID of image. */
168 RTUUID uuidCreate;
169 /** UUID of image's last modification. */
170 RTUUID uuidModify;
171 /** Only for secondary images - UUID of previous image. */
172 RTUUID uuidLinkage;
173 /** Only for secondary images - UUID of previous image's last modification. */
174 RTUUID uuidParentModify;
175} VDIHEADER1, *PVDIHEADER1;
176#pragma pack()
177
178/**
179 * Header structure for all versions.
180 */
181typedef struct VDIHEADER
182{
183 unsigned uVersion;
184 union
185 {
186 VDIHEADER0 v0;
187 VDIHEADER1 v1;
188 } u;
189} VDIHEADER, *PVDIHEADER;
190
191/** Block 'pointer'. */
192typedef uint32_t VDIIMAGEBLOCKPOINTER;
193/** Pointer to a block 'pointer'. */
194typedef VDIIMAGEBLOCKPOINTER *PVDIIMAGEBLOCKPOINTER;
195
196/**
197 * Block marked as free is not allocated in image file, read from this
198 * block may returns any random data.
199 */
200#define VDI_IMAGE_BLOCK_FREE ((VDIIMAGEBLOCKPOINTER)~0)
201
202/**
203 * Block marked as zero is not allocated in image file, read from this
204 * block returns zeroes.
205 */
206#define VDI_IMAGE_BLOCK_ZERO ((VDIIMAGEBLOCKPOINTER)~1)
207
208/**
209 * Block 'pointer' >= VDI_IMAGE_BLOCK_UNALLOCATED indicates block is not
210 * allocated in image file.
211 */
212#define VDI_IMAGE_BLOCK_UNALLOCATED (VDI_IMAGE_BLOCK_ZERO)
213#define IS_VDI_IMAGE_BLOCK_ALLOCATED(bp) (bp < VDI_IMAGE_BLOCK_UNALLOCATED)
214
215#define GET_MAJOR_HEADER_VERSION(ph) (VDI_GET_VERSION_MAJOR((ph)->uVersion))
216#define GET_MINOR_HEADER_VERSION(ph) (VDI_GET_VERSION_MINOR((ph)->uVersion))
217
218
219/*******************************************************************************
220* Internal Functions for header access *
221*******************************************************************************/
222DECLINLINE(VDIIMAGETYPE) getImageType(PVDIHEADER ph)
223{
224 switch (GET_MAJOR_HEADER_VERSION(ph))
225 {
226 case 0: return (VDIIMAGETYPE)ph->u.v0.u32Type;
227 case 1: return (VDIIMAGETYPE)ph->u.v1.u32Type;
228 }
229 AssertFailed();
230 return (VDIIMAGETYPE)0;
231}
232
233DECLINLINE(unsigned) getImageFlags(PVDIHEADER ph)
234{
235 switch (GET_MAJOR_HEADER_VERSION(ph))
236 {
237 case 0: return ph->u.v0.fFlags;
238 case 1: return ph->u.v1.fFlags;
239 }
240 AssertFailed();
241 return 0;
242}
243
244DECLINLINE(char *) getImageComment(PVDIHEADER ph)
245{
246 switch (GET_MAJOR_HEADER_VERSION(ph))
247 {
248 case 0: return &ph->u.v0.szComment[0];
249 case 1: return &ph->u.v1.szComment[0];
250 }
251 AssertFailed();
252 return NULL;
253}
254
255DECLINLINE(unsigned) getImageBlocksOffset(PVDIHEADER ph)
256{
257 switch (GET_MAJOR_HEADER_VERSION(ph))
258 {
259 case 0: return (sizeof(VDIPREHEADER) + sizeof(VDIHEADER0));
260 case 1: return ph->u.v1.offBlocks;
261 }
262 AssertFailed();
263 return 0;
264}
265
266DECLINLINE(unsigned) getImageDataOffset(PVDIHEADER ph)
267{
268 switch (GET_MAJOR_HEADER_VERSION(ph))
269 {
270 case 0: return sizeof(VDIPREHEADER) + sizeof(VDIHEADER0) + \
271 (ph->u.v0.cBlocks * sizeof(VDIIMAGEBLOCKPOINTER));
272 case 1: return ph->u.v1.offData;
273 }
274 AssertFailed();
275 return 0;
276}
277
278DECLINLINE(PVDIDISKGEOMETRY) getImageGeometry(PVDIHEADER ph)
279{
280 switch (GET_MAJOR_HEADER_VERSION(ph))
281 {
282 case 0: return &ph->u.v0.Geometry;
283 case 1: return &ph->u.v1.Geometry;
284 }
285 AssertFailed();
286 return NULL;
287}
288
289DECLINLINE(PDMBIOSTRANSLATION) getImageTranslation(PVDIHEADER ph)
290{
291 switch (GET_MAJOR_HEADER_VERSION(ph))
292 {
293 case 0: return PDMBIOSTRANSLATION_AUTO;
294 case 1: return (PDMBIOSTRANSLATION)ph->u.v1.u32Translation;
295 }
296 AssertFailed();
297 return PDMBIOSTRANSLATION_NONE;
298}
299
300DECLINLINE(void) setImageTranslation(PVDIHEADER ph, PDMBIOSTRANSLATION enmTranslation)
301{
302 switch (GET_MAJOR_HEADER_VERSION(ph))
303 {
304 case 0: return;
305 case 1: ph->u.v1.u32Translation = (uint32_t)enmTranslation; return;
306 }
307 AssertFailed();
308}
309
310DECLINLINE(uint64_t) getImageDiskSize(PVDIHEADER ph)
311{
312 switch (GET_MAJOR_HEADER_VERSION(ph))
313 {
314 case 0: return ph->u.v0.cbDisk;
315 case 1: return ph->u.v1.cbDisk;
316 }
317 AssertFailed();
318 return 0;
319}
320
321DECLINLINE(unsigned) getImageBlockSize(PVDIHEADER ph)
322{
323 switch (GET_MAJOR_HEADER_VERSION(ph))
324 {
325 case 0: return ph->u.v0.cbBlock;
326 case 1: return ph->u.v1.cbBlock;
327 }
328 AssertFailed();
329 return 0;
330}
331
332DECLINLINE(unsigned) getImageExtraBlockSize(PVDIHEADER ph)
333{
334 switch (GET_MAJOR_HEADER_VERSION(ph))
335 {
336 case 0: return 0;
337 case 1: return ph->u.v1.cbBlockExtra;
338 }
339 AssertFailed();
340 return 0;
341}
342
343DECLINLINE(unsigned) getImageBlocks(PVDIHEADER ph)
344{
345 switch (GET_MAJOR_HEADER_VERSION(ph))
346 {
347 case 0: return ph->u.v0.cBlocks;
348 case 1: return ph->u.v1.cBlocks;
349 }
350 AssertFailed();
351 return 0;
352}
353
354DECLINLINE(unsigned) getImageBlocksAllocated(PVDIHEADER ph)
355{
356 switch (GET_MAJOR_HEADER_VERSION(ph))
357 {
358 case 0: return ph->u.v0.cBlocksAllocated;
359 case 1: return ph->u.v1.cBlocksAllocated;
360 }
361 AssertFailed();
362 return 0;
363}
364
365DECLINLINE(void) setImageBlocksAllocated(PVDIHEADER ph, unsigned cBlocks)
366{
367 switch (GET_MAJOR_HEADER_VERSION(ph))
368 {
369 case 0: ph->u.v0.cBlocksAllocated = cBlocks; return;
370 case 1: ph->u.v1.cBlocksAllocated = cBlocks; return;
371 }
372 AssertFailed();
373}
374
375DECLINLINE(PRTUUID) getImageCreationUUID(PVDIHEADER ph)
376{
377 switch (GET_MAJOR_HEADER_VERSION(ph))
378 {
379 case 0: return &ph->u.v0.uuidCreate;
380 case 1: return &ph->u.v1.uuidCreate;
381 }
382 AssertFailed();
383 return NULL;
384}
385
386DECLINLINE(PRTUUID) getImageModificationUUID(PVDIHEADER ph)
387{
388 switch (GET_MAJOR_HEADER_VERSION(ph))
389 {
390 case 0: return &ph->u.v0.uuidModify;
391 case 1: return &ph->u.v1.uuidModify;
392 }
393 AssertFailed();
394 return NULL;
395}
396
397DECLINLINE(PRTUUID) getImageParentUUID(PVDIHEADER ph)
398{
399 switch (GET_MAJOR_HEADER_VERSION(ph))
400 {
401 case 0: return &ph->u.v0.uuidLinkage;
402 case 1: return &ph->u.v1.uuidLinkage;
403 }
404 AssertFailed();
405 return NULL;
406}
407
408DECLINLINE(PRTUUID) getImageParentModificationUUID(PVDIHEADER ph)
409{
410 switch (GET_MAJOR_HEADER_VERSION(ph))
411 {
412 case 1: return &ph->u.v1.uuidParentModify;
413 }
414 AssertFailed();
415 return NULL;
416}
417
418/**
419 * Default image block size, may be changed by setBlockSize/getBlockSize.
420 *
421 * Note: for speed reasons block size should be a power of 2 !
422 */
423#define VDI_IMAGE_DEFAULT_BLOCK_SIZE _1M
424
425/**
426 * fModified bit flags.
427 */
428#define VDI_IMAGE_MODIFIED_FLAG BIT(0)
429#define VDI_IMAGE_MODIFIED_FIRST BIT(1)
430#define VDI_IMAGE_MODIFIED_DISABLE_UUID_UPDATE BIT(2)
431
432/**
433 * Image structure
434 */
435typedef struct VDIIMAGEDESC
436{
437 /** Link to parent image descriptor, if any. */
438 struct VDIIMAGEDESC *pPrev;
439 /** Link to child image descriptor, if any. */
440 struct VDIIMAGEDESC *pNext;
441 /** File handle. */
442 RTFILE File;
443 /** True if the image is operating in readonly mode. */
444 bool fReadOnly;
445 /** Image open flags, VDI_OPEN_FLAGS_*. */
446 unsigned fOpen;
447 /** Image pre-header. */
448 VDIPREHEADER PreHeader;
449 /** Image header. */
450 VDIHEADER Header;
451 /** Pointer to a block array. */
452 PVDIIMAGEBLOCKPOINTER paBlocks;
453 /** fFlags copy from image header, for speed optimization. */
454 unsigned fFlags;
455 /** Start offset of block array in image file, here for speed optimization. */
456 unsigned offStartBlocks;
457 /** Start offset of data in image file, here for speed optimization. */
458 unsigned offStartData;
459 /** Block mask for getting the offset into a block from a byte hdd offset. */
460 unsigned uBlockMask;
461 /** Block shift value for converting byte hdd offset into paBlock index. */
462 unsigned uShiftOffset2Index;
463 /** Block shift value for converting block index into offset in image. */
464 unsigned uShiftIndex2Offset;
465 /** Offset of data from the beginning of block. */
466 unsigned offStartBlockData;
467 /** Image is modified flags (VDI_IMAGE_MODIFIED*). */
468 unsigned fModified;
469 /** Container filename. (UTF-8)
470 * @todo Make this variable length to save a bunch of bytes. (low prio) */
471 char szFilename[RTPATH_MAX];
472} VDIIMAGEDESC, *PVDIIMAGEDESC;
473
474/**
475 * Default work buffer size, may be changed by setBufferSize() method.
476 *
477 * For best speed performance it must be equal to image block size.
478 */
479#define VDIDISK_DEFAULT_BUFFER_SIZE (VDI_IMAGE_DEFAULT_BLOCK_SIZE)
480
481/** VDIDISK Signature. */
482#define VDIDISK_SIGNATURE (0xbedafeda)
483
484/**
485 * VBox HDD Container main structure, private part.
486 */
487struct VDIDISK
488{
489 /** Structure signature (VDIDISK_SIGNATURE). */
490 uint32_t u32Signature;
491
492 /** Number of opened images. */
493 unsigned cImages;
494
495 /** Base image. */
496 PVDIIMAGEDESC pBase;
497
498 /** Last opened image in the chain.
499 * The same as pBase if only one image is used or the last opened diff image. */
500 PVDIIMAGEDESC pLast;
501
502 /** Default block size for newly created images. */
503 unsigned cbBlock;
504
505 /** Working buffer size, allocated only while committing data,
506 * copying block from primary image to secondary and saving previously
507 * zero block. Buffer deallocated after operation complete.
508 * @remark For best performance buffer size must be equal to image's
509 * block size, however it may be decreased for memory saving.
510 */
511 unsigned cbBuf;
512
513 /** Flag whether zero writes should be handled normally or optimized
514 * away if possible. */
515 bool fHonorZeroWrites;
516
517 /** The media interface. */
518 PDMIMEDIA IMedia;
519 /** Pointer to the driver instance. */
520 PPDMDRVINS pDrvIns;
521};
522
523
524/*******************************************************************************
525* Internal Functions *
526*******************************************************************************/
527__BEGIN_DECLS
528
529VBOXDDU_DECL(void) vdiInitVDIDisk(PVDIDISK pDisk);
530VBOXDDU_DECL(void) vdiFlushImage(PVDIIMAGEDESC pImage);
531VBOXDDU_DECL(int) vdiChangeImageMode(PVDIIMAGEDESC pImage, bool fReadOnly);
532
533__END_DECLS
534
535#endif
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