VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp@ 2661

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

Raw disk access VMDKs can now be generated, too.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 111.0 KB
Line 
1/** $Id: VmdkHDDCore.cpp 2661 2007-05-16 11:48:06Z vboxsync $ */
2/** @file
3 * VMDK Disk image, Core Code.
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/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_VD_VMDK
26#include "VBoxHDD-newInternal.h"
27#include <VBox/err.h>
28
29#include <VBox/log.h>
30#include <iprt/assert.h>
31#include <iprt/alloc.h>
32#include <iprt/uuid.h>
33#include <iprt/file.h>
34#include <iprt/path.h>
35#include <iprt/string.h>
36#include <iprt/rand.h>
37
38
39/*******************************************************************************
40* Constants And Macros, Structures and Typedefs *
41*******************************************************************************/
42
43/**
44 * Magic number for hosted images created by VMware Workstation 4, VMware
45 * Workstation 5, VMware Server or VMware Player.
46 */
47#define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
48
49/** VMDK hosted sparse extent header. */
50#pragma pack(1)
51typedef struct SparseExtentHeader
52{
53 uint32_t magicNumber;
54 uint32_t version;
55 uint32_t flags;
56 uint64_t capacity;
57 uint64_t grainSize;
58 uint64_t descriptorOffset;
59 uint64_t descriptorSize;
60 uint32_t numGTEsPerGT;
61 uint64_t rgdOffset;
62 uint64_t gdOffset;
63 uint64_t overHead;
64 bool uncleanShutdown;
65 char singleEndLineChar;
66 char nonEndLineChar;
67 char doubleEndLineChar1;
68 char doubleEndLineChar2;
69 uint8_t pad[435];
70} SparseExtentHeader;
71#pragma pack()
72
73
74#ifdef VBOX_WITH_VMDK_ESX
75
76/** @todo the ESX code is not tested, not used, and lacks error messages. */
77
78/**
79 * Magic number for images created by VMware GSX Server 3 or ESX Server 3.
80 */
81#define VMDK_ESX_SPARSE_MAGICNUMBER 0x44574f43 /* 'C' 'O' 'W' 'D' */
82
83#pragma pack(1)
84typedef struct COWDisk_Header
85{
86 uint32_t magicNumber;
87 uint32_t version;
88 uint32_t flags;
89 uint32_t numSectors;
90 uint32_t grainSize;
91 uint32_t gdOffset;
92 uint32_t numGDEntries;
93 uint32_t freeSector;
94 /* The spec incompletely documents quite a few further fields, but states
95 * that they are not used by the current format. Replace them by padding. */
96 char reserved1[1604];
97 uint32_t savedGeneration;
98 char reserved2[8];
99 uint32_t uncleanShutdown;
100 char padding[396];
101} COWDisk_Header;
102#pragma pack()
103#endif /* VBOX_WITH_VMDK_ESX */
104
105
106/** Convert sector number/size to byte offset/size. */
107#define VMDK_SECTOR2BYTE(u) ((u) << 9)
108
109/** Convert byte offset/size to sector number/size. */
110#define VMDK_BYTE2SECTOR(u) ((u) >> 9)
111
112/**
113 * VMDK extent type.
114 */
115typedef enum VMDKETYPE
116{
117 /** Hosted sparse extent. */
118 VMDKETYPE_HOSTED_SPARSE = 1,
119 /** Flat extent. */
120 VMDKETYPE_FLAT,
121 /** Zero extent. */
122 VMDKETYPE_ZERO
123#ifdef VBOX_WITH_VMDK_ESX
124 ,
125 /** ESX sparse extent. */
126 VMDKETYPE_ESX_SPARSE
127#endif /* VBOX_WITH_VMDK_ESX */
128} VMDKETYPE, *PVMDKETYPE;
129
130/**
131 * VMDK access type for a extent.
132 */
133typedef enum VMDKACCESS
134{
135 /** No access allowed. */
136 VMDKACCESS_NOACCESS = 0,
137 /** Read-only access. */
138 VMDKACCESS_READONLY,
139 /** Read-write access. */
140 VMDKACCESS_READWRITE
141} VMDKACCESS, *PVMDKACCESS;
142
143/**
144 * VMDK extent data structure.
145 */
146typedef struct VMDKEXTENT
147{
148 /** File handle. */
149 RTFILE File;
150 /** Base name of the image extent. */
151 const char *pszBasename;
152 /** Full name of the image extent. */
153 const char *pszFullname;
154 /** Number of sectors in this extent. */
155 uint64_t cSectors;
156 /** Number of sectors per block (grain in VMDK speak). */
157 uint64_t cSectorsPerGrain;
158 /** Starting sector number of descriptor. */
159 uint64_t uDescriptorSector;
160 /** Size of descriptor in sectors. */
161 uint64_t cDescriptorSectors;
162 /** Starting sector number of grain directory. */
163 uint64_t uSectorGD;
164 /** Starting sector number of redundant grain directory. */
165 uint64_t uSectorRGD;
166 /** Total number of metadata sectors. */
167 uint64_t cOverheadSectors;
168 /** Nominal size (i.e. as described by the descriptor) of this extent. */
169 uint64_t cNominalSectors;
170 /** Sector offset (i.e. as described by the descriptor) of this extent. */
171 uint64_t uSectorOffset;
172 /** Number of entries in a grain table. */
173 uint32_t cGTEntries;
174 /** Number of sectors reachable via a grain directory entry. */
175 uint32_t cSectorsPerGDE;
176 /** Number of entries in the grain directory. */
177 uint32_t cGDEntries;
178 /** Pointer to the next free sector. Legacy information. Do not use. */
179 uint32_t uFreeSector;
180 /** Number of this extent in the list of images. */
181 uint32_t uExtent;
182 /** Pointer to the descriptor (NULL if no descriptor in this extent). */
183 char *pDescData;
184 /** Pointer to the grain directory. */
185 uint32_t *pGD;
186 /** Pointer to the redundant grain directory. */
187 uint32_t *pRGD;
188 /** Type of this extent. */
189 VMDKETYPE enmType;
190 /** Access to this extent. */
191 VMDKACCESS enmAccess;
192 /** Flag whether this extent is marked as unclean. */
193 bool fUncleanShutdown;
194 /** Flag whether the metadata in the extent header needs to be updated. */
195 bool fMetaDirty;
196 /** Reference to the image in which this extent is used. Do not use this
197 * on a regular basis to avoid passing pImage references to functions
198 * explicitly. */
199 struct VMDKIMAGE *pImage;
200} VMDKEXTENT, *PVMDKEXTENT;
201
202/**
203 * Grain table cache size. Allocated per image.
204 */
205#define VMDK_GT_CACHE_SIZE 256
206
207/**
208 * Grain table block size. Smaller than an actual grain table block to allow
209 * more grain table blocks to be cached without having to allocate excessive
210 * amounts of memory for the cache.
211 */
212#define VMDK_GT_CACHELINE_SIZE 128
213
214
215/**
216 * Maximum number of lines in a descriptor file. Not worth the effort of
217 * making it variable. Descriptor files are generally very short (~20 lines).
218 */
219#define VMDK_DESCRIPTOR_LINES_MAX 100U
220
221/**
222 * Parsed descriptor information. Allows easy access and update of the
223 * descriptor (whether separate file or not). Free form text files suck.
224 */
225typedef struct VMDKDESCRIPTOR
226{
227 /** Line number of first entry of the disk descriptor. */
228 unsigned uFirstDesc;
229 /** Line number of first entry in the extent description. */
230 unsigned uFirstExtent;
231 /** Line number of first disk database entry. */
232 unsigned uFirstDDB;
233 /** Total number of lines. */
234 unsigned cLines;
235 /** Total amount of memory available for the descriptor. */
236 size_t cbDescAlloc;
237 /** Set if descriptor has been changed and not yet written to disk. */
238 bool fDirty;
239 /** Array of pointers to the data in the descriptor. */
240 char *aLines[VMDK_DESCRIPTOR_LINES_MAX];
241 /** Array of line indices pointing to the next non-comment line. */
242 unsigned aNextLines[VMDK_DESCRIPTOR_LINES_MAX];
243} VMDKDESCRIPTOR, *PVMDKDESCRIPTOR;
244
245
246/**
247 * Cache entry for translating extent/sector to a sector number in that
248 * extent.
249 */
250typedef struct VMDKGTCACHEENTRY
251{
252 /** Extent number for which this entry is valid. */
253 uint32_t uExtent;
254 /** GT data block number. */
255 uint64_t uGTBlock;
256 /** Data part of the cache entry. */
257 uint32_t aGTData[VMDK_GT_CACHELINE_SIZE];
258} VMDKGTCACHEENTRY, *PVMDKGTCACHEENTRY;
259
260/**
261 * Cache data structure for blocks of grain table entries. For now this is a
262 * fixed size direct mapping cache, but this should be adapted to the size of
263 * the sparse image and maybe converted to a set-associative cache. The
264 * implementation below implements a write-through cache with write allocate.
265 */
266typedef struct VMDKGTCACHE
267{
268 /** Cache entries. */
269 VMDKGTCACHEENTRY aGTCache[VMDK_GT_CACHE_SIZE];
270 /** Number of cache entries (currently unused). */
271 unsigned cEntries;
272} VMDKGTCACHE, *PVMDKGTCACHE;
273
274/**
275 * Complete VMDK image data structure. Mainly a collection of extents and a few
276 * extra global data fields.
277 */
278typedef struct VMDKIMAGE
279{
280 PVMDKEXTENT pExtents;
281 unsigned cExtents;
282
283 /** Base image name. */
284 const char *pszFilename;
285 /** Descriptor file if applicable. */
286 RTFILE File;
287
288 /** Error callback. */
289 PFNVDERROR pfnError;
290 /** Opaque data for error callback. */
291 void *pvErrorUser;
292
293 /** Open flags passed by VBoxHD layer. */
294 unsigned uOpenFlags;
295 /** Image type. */
296 VDIMAGETYPE enmImageType;
297 /** Image flags defined during creation or determined during open. */
298 unsigned uImageFlags;
299 /** Total size of the image. */
300 uint64_t cbSize;
301 /** BIOS translation mode. */
302 PDMBIOSTRANSLATION enmTranslation;
303 /** Physical geometry of this image, cylinders. */
304 uint32_t cCylinders;
305 /** Physical geometry of this image, heads. */
306 uint32_t cHeads;
307 /** Physical geometry of this image, sectors. */
308 uint32_t cSectors;
309 /** Image UUID. */
310 RTUUID ImageUuid;
311 /** Image modification UUID. */
312 RTUUID ModificationUuid;
313 /** Parent image UUID. */
314 RTUUID ParentUuid;
315
316 /** Pointer to the grain table cache, if this image contains sparse extents. */
317 PVMDKGTCACHE pGTCache;
318 /** Pointer to the descriptor (NULL if no separate descriptor file). */
319 char *pDescData;
320 /** Allocation size of the descriptor file. */
321 size_t cbDescAlloc;
322 /** Parsed descriptor file content. */
323 VMDKDESCRIPTOR Descriptor;
324} VMDKIMAGE, *PVMDKIMAGE;
325
326
327/*******************************************************************************
328* Internal Functions *
329*******************************************************************************/
330
331static int vmdkReadGrainDirectory(PVMDKEXTENT pExtent);
332static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent);
333
334static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor);
335static int vmdkReadMetaSparseExtent(PVMDKEXTENT pExtent);
336static int vmdkWriteMetaSparseExtent(PVMDKEXTENT pExtent);
337#ifdef VBOX_WITH_VMDK_ESX
338static int vmdkReadMetaESXSparseExtent(PVMDKEXTENT pExtent);
339#endif /* VBOX_WITH_VMDK_ESX */
340static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete);
341
342static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
343static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename, unsigned uOpenFlags);
344static int vmdkFlushImage(PVMDKIMAGE pImage);
345static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
346
347static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData);
348static int vmdkClose(void *pBackendData, bool fDelete);
349
350
351DECLINLINE(int) vmdkError(PVMDKIMAGE pImage, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
352{
353 va_list va;
354 va_start(va, pszFormat);
355 pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
356 va_end(va);
357 return rc;
358}
359
360static int vmdkReadGrainDirectory(PVMDKEXTENT pExtent)
361{
362 int rc = VINF_SUCCESS;
363 unsigned i;
364 uint32_t *pGD = NULL, *pRGD = NULL, *pGDTmp, *pRGDTmp;
365 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
366
367 pGD = (uint32_t *)RTMemAllocZ(cbGD);
368 if (!pGD)
369 {
370 rc = VERR_NO_MEMORY;
371 goto out;
372 }
373 pExtent->pGD = pGD;
374 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD),
375 pGD, cbGD, NULL);
376 AssertRC(rc);
377 if (VBOX_FAILURE(rc))
378 {
379 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s'"), pExtent->pszFullname);
380 goto out;
381 }
382 for (i = 0, pGDTmp = pGD; i < pExtent->cGDEntries; i++, pGDTmp++)
383 *pGDTmp = RT_LE2H_U32(*pGDTmp);
384
385 if (pExtent->uSectorRGD)
386 {
387 pRGD = (uint32_t *)RTMemAllocZ(cbGD);
388 if (!pRGD)
389 {
390 rc = VERR_NO_MEMORY;
391 goto out;
392 }
393 pExtent->pRGD = pRGD;
394 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
395 pRGD, cbGD, NULL);
396 AssertRC(rc);
397 if (VBOX_FAILURE(rc))
398 {
399 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: could not read redundant grain directory in '%s'"), pExtent->pszFullname);
400 goto out;
401 }
402 for (i = 0, pRGDTmp = pRGD; i < pExtent->cGDEntries; i++, pRGDTmp++)
403 *pRGDTmp = RT_LE2H_U32(*pRGDTmp);
404
405 /* Check grain table and redundant grain table for consistency. */
406 size_t cbGT = pExtent->cGTEntries;
407 uint32_t *pTmpGT1 = (uint32_t *)RTMemTmpAlloc(cbGT);
408 if (!pTmpGT1)
409 {
410 rc = VERR_NO_MEMORY;
411 goto out;
412 }
413 uint32_t *pTmpGT2 = (uint32_t *)RTMemTmpAlloc(cbGT);
414 if (!pTmpGT2)
415 {
416 RTMemTmpFree(pTmpGT1);
417 rc = VERR_NO_MEMORY;
418 goto out;
419 }
420
421 for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD; i < pExtent->cGDEntries; i++, pGDTmp++, pRGDTmp++)
422 {
423 /* If no grain table is allocated skip the entry. */
424 if (*pGDTmp == 0 && *pRGDTmp == 0)
425 continue;
426
427 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
428 {
429 /* Just one grain directory entry refers to a not yet allocated
430 * grain table or both grain directory copies refer to the same
431 * grain table. Not allowed. */
432 RTMemTmpFree(pTmpGT1);
433 RTMemTmpFree(pTmpGT2);
434 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname);
435 goto out;
436 }
437 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pGDTmp),
438 pTmpGT1, cbGT, NULL);
439 if (VBOX_FAILURE(rc))
440 {
441 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname);
442 RTMemTmpFree(pTmpGT1);
443 RTMemTmpFree(pTmpGT2);
444 goto out;
445 }
446 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pRGDTmp),
447 pTmpGT2, cbGT, NULL);
448 if (VBOX_FAILURE(rc))
449 {
450 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading backup grain table in '%s'"), pExtent->pszFullname);
451 RTMemTmpFree(pTmpGT1);
452 RTMemTmpFree(pTmpGT2);
453 goto out;
454 }
455 if (memcmp(pTmpGT1, pTmpGT2, cbGT))
456 {
457 RTMemTmpFree(pTmpGT1);
458 RTMemTmpFree(pTmpGT2);
459 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname);
460 goto out;
461 }
462 }
463
464 /** @todo figure out what to do for unclean VMDKs. */
465 }
466
467out:
468 if (VBOX_FAILURE(rc))
469 vmdkFreeGrainDirectory(pExtent);
470 return rc;
471}
472
473static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector, bool fPreAlloc)
474{
475 int rc = VINF_SUCCESS;
476 unsigned i;
477 uint32_t *pGD = NULL, *pRGD = NULL;
478 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
479 size_t cbGDRounded = RT_ALIGN_64(pExtent->cGDEntries * sizeof(uint32_t), 512);
480 size_t cbGTRounded;
481 uint64_t cbOverhead;
482
483 if (fPreAlloc)
484 cbGTRounded = RT_ALIGN_64(pExtent->cGDEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
485 else
486 cbGTRounded = 0;
487
488 pGD = (uint32_t *)RTMemAllocZ(cbGD);
489 if (!pGD)
490 {
491 rc = VERR_NO_MEMORY;
492 goto out;
493 }
494 pExtent->pGD = pGD;
495 pRGD = (uint32_t *)RTMemAllocZ(cbGD);
496 if (!pRGD)
497 {
498 rc = VERR_NO_MEMORY;
499 goto out;
500 }
501 pExtent->pRGD = pRGD;
502
503 cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
504 rc = RTFileSetSize(pExtent->File, cbOverhead);
505 if (VBOX_FAILURE(rc))
506 goto out;
507 pExtent->uSectorRGD = uStartSector;
508 pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
509
510 if (fPreAlloc)
511 {
512 uint32_t uGTSectorLE;
513 uint32_t uOffsetSectors;
514
515 uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded);
516 for (i = 0; i < pExtent->cGDEntries; i++)
517 {
518 pRGD[i] = uOffsetSectors;
519 uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
520 /* Write the redundant grain directory entry to disk. */
521 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
522 if (VBOX_FAILURE(rc))
523 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
524 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
525 }
526
527 uOffsetSectors = pExtent->uSectorGD + VMDK_BYTE2SECTOR(cbGDRounded);
528 for (i = 0; i < pExtent->cGDEntries; i++)
529 {
530 pGD[i] = uOffsetSectors;
531 uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
532 /* Write the grain directory entry to disk. */
533 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
534 if (VBOX_FAILURE(rc))
535 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
536 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
537 }
538 }
539 pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
540
541out:
542 if (VBOX_FAILURE(rc))
543 vmdkFreeGrainDirectory(pExtent);
544 return rc;
545}
546
547static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent)
548{
549 if (pExtent->pszBasename)
550 {
551 RTMemTmpFree((void *)pExtent->pszBasename);
552 pExtent->pszBasename = NULL;
553 }
554 if (pExtent->pGD)
555 {
556 RTMemFree(pExtent->pGD);
557 pExtent->pGD = NULL;
558 }
559 if (pExtent->pRGD)
560 {
561 RTMemFree(pExtent->pRGD);
562 pExtent->pRGD = NULL;
563 }
564}
565
566static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr, char **ppszUnquoted, char **ppszNext)
567{
568 char *pszQ;
569 char *pszUnquoted;
570
571 /* Skip over whitespace. */
572 while (*pszStr == ' ' || *pszStr == '\t')
573 pszStr++;
574 if (*pszStr++ != '"')
575 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s'"), pImage->pszFilename);
576
577 pszQ = (char*)strchr(pszStr, '"');
578 if (pszQ == NULL)
579 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s'"), pImage->pszFilename);
580 pszUnquoted = (char *)RTMemTmpAlloc(pszQ - pszStr + 1);
581 if (!pszUnquoted)
582 return VERR_NO_MEMORY;
583 memcpy(pszUnquoted, pszStr, pszQ - pszStr);
584 pszUnquoted[pszQ - pszStr] = '\0';
585 *ppszUnquoted = pszUnquoted;
586 if (ppszNext)
587 *ppszNext = pszQ + 1;
588 return VINF_SUCCESS;
589}
590
591static int vmdkDescInitStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
592 const char *pszLine)
593{
594 char *pEnd = pDescriptor->aLines[pDescriptor->cLines];
595 ssize_t cbDiff = strlen(pszLine) + 1;
596
597 if ( pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1
598 && pEnd - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
599 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
600
601 memcpy(pEnd, pszLine, cbDiff);
602 pDescriptor->cLines++;
603 pDescriptor->aLines[pDescriptor->cLines] = pEnd + cbDiff;
604 pDescriptor->fDirty = true;
605
606 return VINF_SUCCESS;
607}
608
609static bool vmdkDescGetStr(PVMDKDESCRIPTOR pDescriptor, unsigned uStart,
610 const char *pszKey, const char **ppszValue)
611{
612 size_t cbKey = strlen(pszKey);
613 const char *pszValue;
614
615 while (uStart != 0)
616 {
617 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
618 {
619 /* Key matches, check if there is a '=' (preceded by whitespace). */
620 pszValue = pDescriptor->aLines[uStart] + cbKey;
621 while (*pszValue == ' ' || *pszValue == '\t')
622 pszValue++;
623 if (*pszValue == '=')
624 {
625 *ppszValue = pszValue + 1;
626 break;
627 }
628 }
629 uStart = pDescriptor->aNextLines[uStart];
630 }
631 return !!uStart;
632}
633
634static int vmdkDescSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
635 unsigned uStart,
636 const char *pszKey, const char *pszValue)
637{
638 char *pszTmp;
639 size_t cbKey = strlen(pszKey);
640 unsigned uLast = 0;
641
642 while (uStart != 0)
643 {
644 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
645 {
646 /* Key matches, check if there is a '=' (preceded by whitespace). */
647 pszTmp = pDescriptor->aLines[uStart] + cbKey;
648 while (*pszTmp == ' ' || *pszTmp == '\t')
649 pszTmp++;
650 if (*pszTmp == '=')
651 {
652 while (*pszTmp == ' ' || *pszTmp == '\t')
653 pszTmp++;
654 break;
655 }
656 }
657 if (!pDescriptor->aNextLines[uStart])
658 uLast = uStart;
659 uStart = pDescriptor->aNextLines[uStart];
660 }
661 if (uStart)
662 {
663 /* Key already exists, replace existing value. */
664 size_t cbOldVal = strlen(pszTmp);
665 size_t cbNewVal = strlen(pszValue);
666 ssize_t cbDiff = cbNewVal - cbOldVal;
667 /* Check for buffer overflow. */
668 if ( pDescriptor->aLines[pDescriptor->cLines]
669 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
670 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
671
672 memmove(pszTmp + cbNewVal, pszTmp + cbOldVal,
673 pDescriptor->aLines[pDescriptor->cLines] - pszTmp - cbOldVal);
674 memcpy(pszTmp, pszValue, cbNewVal + 1);
675 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
676 pDescriptor->aLines[i] += cbDiff;
677 }
678 else
679 {
680 /* Key doesn't exist, append it after the last entry in this category. */
681 size_t cbKey = strlen(pszKey);
682 size_t cbValue = strlen(pszValue);
683 ssize_t cbDiff = cbKey + 1 + cbValue + 1;
684 /* Check for buffer overflow. */
685 if ( (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
686 || ( pDescriptor->aLines[pDescriptor->cLines]
687 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
688 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
689 for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
690 {
691 pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
692 if (pDescriptor->aNextLines[i - 1])
693 pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
694 else
695 pDescriptor->aNextLines[i] = 0;
696 }
697 uStart = uLast + 1;
698 pDescriptor->aNextLines[uLast] = uStart;
699 pDescriptor->aNextLines[uStart] = 0;
700 pDescriptor->cLines++;
701 pszTmp = pDescriptor->aLines[uStart];
702 memmove(pszTmp + cbDiff, pszTmp,
703 pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
704 memcpy(pDescriptor->aLines[uStart], pszKey, cbKey);
705 pDescriptor->aLines[uStart][cbKey] = '=';
706 memcpy(pDescriptor->aLines[uStart] + cbKey + 1, pszValue, cbValue + 1);
707 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
708 pDescriptor->aLines[i] += cbDiff;
709
710 /* Adjust starting line numbers of following descriptor sections. */
711 if (uStart <= pDescriptor->uFirstExtent)
712 pDescriptor->uFirstExtent++;
713 if (uStart <= pDescriptor->uFirstDDB)
714 pDescriptor->uFirstDDB++;
715 }
716 pDescriptor->fDirty = true;
717 return VINF_SUCCESS;
718}
719
720static int vmdkDescBaseGetU32(PVMDKDESCRIPTOR pDescriptor, const char *pszKey,
721 uint32_t *puValue)
722{
723 const char *pszValue;
724
725 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, &pszValue))
726 return VERR_VDI_VALUE_NOT_FOUND;
727 return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
728}
729
730static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor)
731{
732 unsigned uEntry = pDescriptor->uFirstExtent;
733 ssize_t cbDiff;
734
735 if (!uEntry)
736 return;
737
738 cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
739 /* Move everything including the \0 in the entry marking the end of buffer. */
740 memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
741 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
742 for (unsigned i = uEntry + 1; i <= pDescriptor->cLines; i++)
743 {
744 pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff;
745 if (pDescriptor->aNextLines[i])
746 pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1;
747 else
748 pDescriptor->aNextLines[i - 1] = 0;
749 }
750 pDescriptor->cLines--;
751 if (pDescriptor->uFirstDDB)
752 pDescriptor->uFirstDDB--;
753
754 return;
755}
756
757static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
758 VMDKACCESS enmAccess, uint64_t cNominalSectors,
759 VMDKETYPE enmType, const char *pszBasename,
760 uint64_t uSectorOffset)
761{
762 static const char *apszAccess[] = { "NOACCESS", "RDONLY", "RW" };
763 static const char *apszType[] = { "", "SPARSE", "FLAT", "ZERO" };
764 char *pszTmp;
765 unsigned uStart = pDescriptor->uFirstExtent, uLast;
766 char szExt[1024];
767 ssize_t cbDiff;
768
769 /* Find last entry in extent description. */
770 while (uStart)
771 {
772 if (!pDescriptor->aNextLines[uStart])
773 uLast = uStart;
774 uStart = pDescriptor->aNextLines[uStart];
775 }
776
777 if (enmType == VMDKETYPE_ZERO)
778 {
779 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s ", apszAccess[enmAccess],
780 cNominalSectors, apszType[enmType]);
781 }
782 else
783 {
784 if (!uSectorOffset)
785 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\"",
786 apszAccess[enmAccess], cNominalSectors,
787 apszType[enmType], pszBasename);
788 else
789 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\" %llu",
790 apszAccess[enmAccess], cNominalSectors,
791 apszType[enmType], pszBasename, uSectorOffset);
792 }
793 cbDiff = strlen(szExt) + 1;
794
795 /* Check for buffer overflow. */
796 if ( (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
797 || ( pDescriptor->aLines[pDescriptor->cLines]
798 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
799 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
800
801 for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
802 {
803 pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
804 if (pDescriptor->aNextLines[i - 1])
805 pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
806 else
807 pDescriptor->aNextLines[i] = 0;
808 }
809 uStart = uLast + 1;
810 pDescriptor->aNextLines[uLast] = uStart;
811 pDescriptor->aNextLines[uStart] = 0;
812 pDescriptor->cLines++;
813 pszTmp = pDescriptor->aLines[uStart];
814 memmove(pszTmp + cbDiff, pszTmp,
815 pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
816 memcpy(pDescriptor->aLines[uStart], szExt, cbDiff);
817 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
818 pDescriptor->aLines[i] += cbDiff;
819
820 /* Adjust starting line numbers of following descriptor sections. */
821 if (uStart <= pDescriptor->uFirstDDB)
822 pDescriptor->uFirstDDB++;
823
824 pDescriptor->fDirty = true;
825 return VINF_SUCCESS;
826}
827
828static int vmdkDescDDBGetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
829 const char *pszKey, uint32_t *puValue)
830{
831 const char *pszValue;
832 char *pszValueUnquoted;
833
834 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
835 return VERR_VDI_VALUE_NOT_FOUND;
836 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
837 if (VBOX_FAILURE(rc))
838 return rc;
839 rc = RTStrToUInt32Ex(pszValueUnquoted, NULL, 10, puValue);
840 RTMemTmpFree(pszValueUnquoted);
841 return rc;
842}
843
844static int vmdkDescDDBGetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
845 const char *pszKey, PRTUUID pUuid)
846{
847 const char *pszValue;
848 char *pszValueUnquoted;
849
850 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
851 return VERR_VDI_VALUE_NOT_FOUND;
852 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
853 if (VBOX_FAILURE(rc))
854 return rc;
855 rc = RTUuidFromStr(pUuid, pszValueUnquoted);
856 RTMemTmpFree(pszValueUnquoted);
857 return rc;
858}
859
860int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, const char *pszVal)
861{
862 char *pszValQuoted;
863
864 int rc = RTStrAPrintf(&pszValQuoted, "\"%s\"", pszVal);
865 if (VBOX_FAILURE(rc))
866 return rc;
867 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValQuoted);
868 RTStrFree(pszValQuoted);
869 return rc;
870}
871
872int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, PCRTUUID pUuid)
873{
874 char *pszUuid;
875
876 int rc = RTStrAPrintf(&pszUuid, "\"%Vuuid\"", pUuid);
877 if (VBOX_FAILURE(rc))
878 return rc;
879 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszUuid);
880 RTStrFree(pszUuid);
881 return rc;
882}
883
884int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, uint32_t uValue)
885{
886 char *pszValue;
887
888 int rc = RTStrAPrintf(&pszValue, "\"%d\"", uValue);
889 if (VBOX_FAILURE(rc))
890 return rc;
891 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValue);
892 RTStrFree(pszValue);
893 return rc;
894}
895
896static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
897{
898 int rc = VINF_SUCCESS;
899 unsigned cLine = 0, uLastNonEmptyLine = 0;
900 char *pTmp = pDescData;
901
902 pDescriptor->cbDescAlloc = cbDescData;
903 while (*pTmp != '\0')
904 {
905 pDescriptor->aLines[cLine++] = pTmp;
906 if (cLine >= VMDK_DESCRIPTOR_LINES_MAX)
907 {
908 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
909 goto out;
910 }
911
912 while (*pTmp != '\0' && *pTmp != '\n')
913 {
914 if (*pTmp == '\r')
915 {
916 if (*(pTmp + 1) != '\n')
917 {
918 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: unsupported end of line in descriptor in '%s'"), pImage->pszFilename);
919 goto out;
920 }
921 else
922 {
923 /* Get rid of CR character. */
924 *pTmp = '\0';
925 }
926 }
927 pTmp++;
928 }
929 /* Get rid of LF character. */
930 if (*pTmp == '\n')
931 {
932 *pTmp = '\0';
933 pTmp++;
934 }
935 }
936 pDescriptor->cLines = cLine;
937 /* Pointer right after the end of the used part of the buffer. */
938 pDescriptor->aLines[cLine] = pTmp;
939
940 if (strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile"))
941 {
942 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename);
943 goto out;
944 }
945
946 /* Initialize those, because we need to be able to reopen an image. */
947 pDescriptor->uFirstDesc = 0;
948 pDescriptor->uFirstExtent = 0;
949 pDescriptor->uFirstDDB = 0;
950 for (unsigned i = 0; i < cLine; i++)
951 {
952 if (*pDescriptor->aLines[i] != '#' && *pDescriptor->aLines[i] != '\0')
953 {
954 if ( !strncmp(pDescriptor->aLines[i], "RW", 2)
955 || !strncmp(pDescriptor->aLines[i], "RDONLY", 6)
956 || !strncmp(pDescriptor->aLines[i], "NOACCESS", 8) )
957 {
958 /* An extent descriptor. */
959 if (!pDescriptor->uFirstDesc || pDescriptor->uFirstDDB)
960 {
961 /* Incorrect ordering of entries. */
962 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
963 goto out;
964 }
965 if (!pDescriptor->uFirstExtent)
966 {
967 pDescriptor->uFirstExtent = i;
968 uLastNonEmptyLine = 0;
969 }
970 }
971 else if (!strncmp(pDescriptor->aLines[i], "ddb.", 4))
972 {
973 /* A disk database entry. */
974 if (!pDescriptor->uFirstDesc || !pDescriptor->uFirstExtent)
975 {
976 /* Incorrect ordering of entries. */
977 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
978 goto out;
979 }
980 if (!pDescriptor->uFirstDDB)
981 {
982 pDescriptor->uFirstDDB = i;
983 uLastNonEmptyLine = 0;
984 }
985 }
986 else
987 {
988 /* A normal entry. */
989 if (pDescriptor->uFirstExtent || pDescriptor->uFirstDDB)
990 {
991 /* Incorrect ordering of entries. */
992 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
993 goto out;
994 }
995 if (!pDescriptor->uFirstDesc)
996 {
997 pDescriptor->uFirstDesc = i;
998 uLastNonEmptyLine = 0;
999 }
1000 }
1001 if (uLastNonEmptyLine)
1002 pDescriptor->aNextLines[uLastNonEmptyLine] = i;
1003 uLastNonEmptyLine = i;
1004 }
1005 }
1006
1007out:
1008 return rc;
1009}
1010
1011static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
1012{
1013 int rc;
1014
1015 pDescriptor->uFirstDesc = 0;
1016 pDescriptor->uFirstExtent = 0;
1017 pDescriptor->uFirstDDB = 0;
1018 pDescriptor->cLines = 0;
1019 pDescriptor->cbDescAlloc = cbDescData;
1020 pDescriptor->fDirty = false;
1021 pDescriptor->aLines[pDescriptor->cLines] = pDescData;
1022 memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
1023
1024 rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile");
1025 if (VBOX_FAILURE(rc))
1026 goto out;
1027 rc = vmdkDescInitStr(pImage, pDescriptor, "version=1");
1028 if (VBOX_FAILURE(rc))
1029 goto out;
1030 pDescriptor->uFirstDesc = pDescriptor->cLines - 1;
1031 rc = vmdkDescInitStr(pImage, pDescriptor, "");
1032 if (VBOX_FAILURE(rc))
1033 goto out;
1034 rc = vmdkDescInitStr(pImage, pDescriptor, "# Extent description");
1035 if (VBOX_FAILURE(rc))
1036 goto out;
1037 rc = vmdkDescInitStr(pImage, pDescriptor, "NOACCESS 0 ZERO ");
1038 if (VBOX_FAILURE(rc))
1039 goto out;
1040 pDescriptor->uFirstExtent = pDescriptor->cLines - 1;
1041 rc = vmdkDescInitStr(pImage, pDescriptor, "");
1042 if (VBOX_FAILURE(rc))
1043 goto out;
1044 /* The trailing space is created by VMware, too. */
1045 rc = vmdkDescInitStr(pImage, pDescriptor, "# The disk Data Base ");
1046 if (VBOX_FAILURE(rc))
1047 goto out;
1048 rc = vmdkDescInitStr(pImage, pDescriptor, "#DDB");
1049 if (VBOX_FAILURE(rc))
1050 goto out;
1051 rc = vmdkDescInitStr(pImage, pDescriptor, "");
1052 if (VBOX_FAILURE(rc))
1053 goto out;
1054 rc = vmdkDescInitStr(pImage, pDescriptor, "ddb.virtualHWVersion = \"4\"");
1055 if (VBOX_FAILURE(rc))
1056 goto out;
1057 pDescriptor->uFirstDDB = pDescriptor->cLines - 1;
1058
1059 /* Now that the framework is in place, use the normal functions to insert
1060 * the remaining keys. */
1061 char szBuf[9];
1062 RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32());
1063 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "CID", szBuf);
1064 if (VBOX_FAILURE(rc))
1065 goto out;
1066 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "parentCID", "ffffffff");
1067 if (VBOX_FAILURE(rc))
1068 goto out;
1069
1070 rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide");
1071 if (VBOX_FAILURE(rc))
1072 goto out;
1073
1074out:
1075 return rc;
1076}
1077
1078static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
1079{
1080 int rc;
1081 unsigned cExtents;
1082 unsigned uLine;
1083
1084 rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData, &pImage->Descriptor);
1085 if (VBOX_FAILURE(rc))
1086 return rc;
1087
1088 /* Check version, must be 1. */
1089 uint32_t uVersion;
1090 rc = vmdkDescBaseGetU32(&pImage->Descriptor, "version", &uVersion);
1091 if (VBOX_FAILURE(rc))
1092 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error finding key 'version' in descriptor in '%s'"), pImage->pszFilename);
1093 if (uVersion != 1)
1094 return vmdkError(pImage, VERR_VDI_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor in '%s'"), pImage->pszFilename);
1095
1096 /* Count the number of extent config entries. */
1097 for (uLine = pImage->Descriptor.uFirstExtent, cExtents = 0;
1098 uLine != 0;
1099 uLine = pImage->Descriptor.aNextLines[uLine], cExtents++)
1100 /* nothing */;
1101
1102 if (!pImage->pDescData && cExtents != 1)
1103 {
1104 /* Monolithic image, must have only one extent (already opened). */
1105 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image may only have one extent in '%s'"), pImage->pszFilename);
1106 }
1107
1108 if (pImage->pDescData)
1109 {
1110 /* Non-monolithic image, extents need to be allocated. */
1111 rc = vmdkCreateExtents(pImage, cExtents);
1112 if (VBOX_FAILURE(rc))
1113 return rc;
1114 }
1115
1116 for (unsigned i = 0, uLine = pImage->Descriptor.uFirstExtent;
1117 i < cExtents; i++, uLine = pImage->Descriptor.aNextLines[uLine])
1118 {
1119 char *pszLine = pImage->Descriptor.aLines[uLine];
1120
1121 /* Access type of the extent. */
1122 if (!strncmp(pszLine, "RW", 2))
1123 {
1124 pImage->pExtents[i].enmAccess = VMDKACCESS_READWRITE;
1125 pszLine += 2;
1126 }
1127 else if (!strncmp(pszLine, "RDONLY", 6))
1128 {
1129 pImage->pExtents[i].enmAccess = VMDKACCESS_READONLY;
1130 pszLine += 6;
1131 }
1132 else if (!strncmp(pszLine, "NOACCESS", 8))
1133 {
1134 pImage->pExtents[i].enmAccess = VMDKACCESS_NOACCESS;
1135 pszLine += 8;
1136 }
1137 else
1138 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1139 if (*pszLine++ != ' ')
1140 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1141
1142 /* Nominal size of the extent. */
1143 rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
1144 &pImage->pExtents[i].cNominalSectors);
1145 if (VBOX_FAILURE(rc))
1146 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1147 if (*pszLine++ != ' ')
1148 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1149
1150 /* Type of the extent. */
1151#ifdef VBOX_WITH_VMDK_ESX
1152 /** @todo Add the ESX extent types. Not necessary for now because
1153 * the ESX extent types are only used inside an ESX server. They are
1154 * automatically converted if the VMDK is exported. */
1155#endif /* VBOX_WITH_VMDK_ESX */
1156 if (!strncmp(pszLine, "SPARSE", 6))
1157 {
1158 pImage->pExtents[i].enmType = VMDKETYPE_HOSTED_SPARSE;
1159 pszLine += 6;
1160 }
1161 else if (!strncmp(pszLine, "FLAT", 4))
1162 {
1163 pImage->pExtents[i].enmType = VMDKETYPE_FLAT;
1164 pszLine += 4;
1165 }
1166 else if (!strncmp(pszLine, "ZERO", 4))
1167 {
1168 pImage->pExtents[i].enmType = VMDKETYPE_ZERO;
1169 pszLine += 4;
1170 }
1171 else
1172 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1173 if (pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
1174 {
1175 /* This one has no basename or offset. */
1176 if (*pszLine == ' ')
1177 pszLine++;
1178 if (*pszLine != '\0')
1179 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1180 pImage->pExtents[i].pszBasename = NULL;
1181 }
1182 else
1183 {
1184 /* All other extent types have basename and optional offset. */
1185 if (*pszLine++ != ' ')
1186 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1187
1188 /* Basename of the image. Surrounded by quotes. */
1189 char *pszBasename;
1190 rc = vmdkStringUnquote(pImage, pszLine, &pszBasename, &pszLine);
1191 if (VBOX_FAILURE(rc))
1192 return rc;
1193 pImage->pExtents[i].pszBasename = pszBasename;
1194 if (*pszLine == ' ')
1195 {
1196 pszLine++;
1197 if (*pszLine != '\0')
1198 {
1199 /* Optional offset in extent specified. */
1200 rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
1201 &pImage->pExtents[i].uSectorOffset);
1202 if (VBOX_FAILURE(rc))
1203 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1204 }
1205 }
1206
1207 if (*pszLine != '\0')
1208 return vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
1209 }
1210 }
1211
1212 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
1213 "ddb.geometry.cylinders", &pImage->cCylinders);
1214 if (VBOX_FAILURE(rc))
1215 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
1216 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
1217 "ddb.geometry.heads", &pImage->cHeads);
1218 if (VBOX_FAILURE(rc))
1219 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
1220 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
1221 "ddb.geometry.sectors", &pImage->cSectors);
1222 if (VBOX_FAILURE(rc))
1223 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
1224 if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
1225 pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
1226 else
1227 pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;
1228
1229 /* Get image UUID. */
1230 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, "ddb.uuid.image",
1231 &pImage->ImageUuid);
1232 if (rc == VERR_VDI_VALUE_NOT_FOUND)
1233 {
1234 /* Image without UUID. Probably created by VMware and not yet used
1235 * by VirtualBox. Can only be added for images opened in read/write
1236 * mode, so don't bother producing a sensible UUID otherwise. */
1237 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1238 RTUuidClear(&pImage->ImageUuid);
1239 else
1240 {
1241 rc = RTUuidCreate(&pImage->ImageUuid);
1242 if (VBOX_FAILURE(rc))
1243 return rc;
1244 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
1245 "ddb.uuid.image", &pImage->ImageUuid);
1246 if (VBOX_FAILURE(rc))
1247 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
1248 }
1249 }
1250 else if (VBOX_FAILURE(rc))
1251 return rc;
1252
1253 /* Get image modification UUID. */
1254 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, "ddb.uuid.modification",
1255 &pImage->ModificationUuid);
1256 if (rc == VERR_VDI_VALUE_NOT_FOUND)
1257 {
1258 /* Image without UUID. Probably created by VMware and not yet used
1259 * by VirtualBox. Can only be added for images opened in read/write
1260 * mode, so don't bother producing a sensible UUID otherwise. */
1261 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1262 RTUuidClear(&pImage->ModificationUuid);
1263 else
1264 {
1265 rc = RTUuidCreate(&pImage->ModificationUuid);
1266 if (VBOX_FAILURE(rc))
1267 return rc;
1268 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
1269 "ddb.uuid.modification", &pImage->ModificationUuid);
1270 if (VBOX_FAILURE(rc))
1271 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename);
1272 }
1273 }
1274 else if (VBOX_FAILURE(rc))
1275 return rc;
1276
1277 /* Get UUID of parent image. */
1278 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, "ddb.uuid.parent",
1279 &pImage->ParentUuid);
1280 if (rc == VERR_VDI_VALUE_NOT_FOUND)
1281 {
1282 /* Image without UUID. Probably created by VMware and not yet used
1283 * by VirtualBox. Can only be added for images opened in read/write
1284 * mode, so don't bother producing a sensible UUID otherwise. */
1285 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1286 RTUuidClear(&pImage->ParentUuid);
1287 else
1288 {
1289 rc = RTUuidClear(&pImage->ParentUuid);
1290 if (VBOX_FAILURE(rc))
1291 return rc;
1292 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
1293 "ddb.uuid.parent", &pImage->ParentUuid);
1294 if (VBOX_FAILURE(rc))
1295 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent UUID in descriptor in '%s'"), pImage->pszFilename);
1296 }
1297 }
1298 else if (VBOX_FAILURE(rc))
1299 return rc;
1300
1301 return VINF_SUCCESS;
1302}
1303
1304static int vmdkWriteDescriptor(PVMDKIMAGE pImage)
1305{
1306 int rc = VINF_SUCCESS;
1307 uint64_t cbLimit;
1308 uint64_t uOffset;
1309 RTFILE DescFile;
1310
1311 if (pImage->pDescData)
1312 {
1313 /* Separate descriptor file. */
1314 uOffset = 0;
1315 cbLimit = 0;
1316 DescFile = pImage->File;
1317 }
1318 else
1319 {
1320 /* Embedded descriptor file. */
1321 uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector);
1322 cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
1323 cbLimit += uOffset;
1324 DescFile = pImage->pExtents[0].File;
1325 }
1326 for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
1327 {
1328 const char *psz = pImage->Descriptor.aLines[i];
1329 size_t cb = strlen(psz);
1330
1331 if (cbLimit && uOffset + cb + 1 > cbLimit)
1332 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
1333 rc = RTFileWriteAt(DescFile, uOffset, psz, cb, NULL);
1334 if (VBOX_FAILURE(rc))
1335 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
1336 uOffset += cb;
1337 rc = RTFileWriteAt(DescFile, uOffset, "\n", 1, NULL);
1338 if (VBOX_FAILURE(rc))
1339 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
1340 uOffset++;
1341 }
1342 if (cbLimit)
1343 {
1344 /* Inefficient, but simple. */
1345 while (uOffset < cbLimit)
1346 {
1347 rc = RTFileWriteAt(DescFile, uOffset, "", 1, NULL);
1348 if (VBOX_FAILURE(rc))
1349 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
1350 uOffset++;
1351 }
1352 }
1353 else
1354 {
1355 rc = RTFileSetSize(DescFile, uOffset);
1356 if (VBOX_FAILURE(rc))
1357 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
1358 }
1359 pImage->Descriptor.fDirty = false;
1360 return rc;
1361}
1362
1363static int vmdkReadMetaSparseExtent(PVMDKEXTENT pExtent)
1364{
1365 SparseExtentHeader Header;
1366 uint64_t cbExtentSize, cSectorsPerGDE;
1367
1368 int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
1369 AssertRC(rc);
1370 if (VBOX_FAILURE(rc))
1371 {
1372 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
1373 goto out;
1374 }
1375 if ( RT_LE2H_U32(Header.magicNumber) != VMDK_SPARSE_MAGICNUMBER
1376 || RT_LE2H_U32(Header.version) != 1)
1377 {
1378 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic/version in extent header in '%s'"), pExtent->pszFullname);
1379 goto out;
1380 }
1381 /* The image must be a multiple of a sector in size. If not, it means the
1382 * image is at least truncated, or even seriously garbled. */
1383 rc = RTFileGetSize(pExtent->File, &cbExtentSize);
1384 if (VBOX_FAILURE(rc))
1385 {
1386 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
1387 goto out;
1388 }
1389 if ( (RT_LE2H_U32(Header.flags) & 1)
1390 && ( Header.singleEndLineChar != '\n'
1391 || Header.nonEndLineChar != ' '
1392 || Header.doubleEndLineChar1 != '\r'
1393 || Header.doubleEndLineChar2 != '\n') )
1394 {
1395 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname);
1396 goto out;
1397 }
1398 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
1399 pExtent->cSectors = RT_LE2H_U64(Header.capacity);
1400 pExtent->cSectorsPerGrain = RT_LE2H_U64(Header.grainSize);
1401 /* The spec says that this must be a power of two and greater than 8,
1402 * but probably they meant not less than 8. */
1403 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))
1404 || pExtent->cSectorsPerGrain < 8)
1405 {
1406 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
1407 goto out;
1408 }
1409 pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset);
1410 pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize);
1411 if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
1412 {
1413 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
1414 goto out;
1415 }
1416 pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT);
1417 /* This code requires that a grain table must hold a power of two multiple
1418 * of the number of entries per GT cache entry. */
1419 if ( (pExtent->cGTEntries & (pExtent->cGTEntries - 1))
1420 || pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE)
1421 {
1422 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);
1423 goto out;
1424 }
1425 if (RT_LE2H_U32(Header.flags) & 2)
1426 {
1427 pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset);
1428 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
1429 }
1430 else
1431 {
1432 /** @todo this is just guesswork, the spec doesn't document this
1433 * properly and I don't have a vmdk without RGD. */
1434 pExtent->uSectorGD = RT_LE2H_U64(Header.rgdOffset);
1435 pExtent->uSectorRGD = 0;
1436 }
1437 pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
1438 pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
1439 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
1440 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
1441 {
1442 rc = vmdkError(pExtent->pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
1443 goto out;
1444 }
1445 pExtent->cSectorsPerGDE = cSectorsPerGDE;
1446 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
1447
1448 rc = vmdkReadGrainDirectory(pExtent);
1449
1450out:
1451 if (VBOX_FAILURE(rc))
1452 vmdkFreeExtentData(pExtent, false);
1453
1454 return rc;
1455}
1456
1457static int vmdkWriteMetaSparseExtent(PVMDKEXTENT pExtent)
1458{
1459 SparseExtentHeader Header;
1460
1461 memset(&Header, '\0', sizeof(Header));
1462 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
1463 Header.version = RT_H2LE_U32(1);
1464 Header.flags = RT_H2LE_U32(1 | ((pExtent->pRGD) ? 2 : 0));
1465 Header.capacity = RT_H2LE_U64(pExtent->cSectors);
1466 Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
1467 Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector);
1468 Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
1469 Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
1470 if (pExtent->pRGD)
1471 {
1472 Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
1473 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
1474 }
1475 else
1476 {
1477 /** @todo this is just guesswork, the spec doesn't document this
1478 * properly and I don't have a vmdk without RGD. */
1479 Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorGD);
1480 }
1481 Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
1482 Header.uncleanShutdown = pExtent->fUncleanShutdown;
1483 Header.singleEndLineChar = '\n';
1484 Header.nonEndLineChar = ' ';
1485 Header.doubleEndLineChar1 = '\r';
1486 Header.doubleEndLineChar2 = '\n';
1487
1488 int rc = RTFileWriteAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
1489 AssertRC(rc);
1490 if (VBOX_FAILURE(rc))
1491 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname);
1492 return rc;
1493}
1494
1495#ifdef VBOX_WITH_VMDK_ESX
1496static int vmdkReadMetaESXSparseExtent(PVMDKEXTENT pExtent)
1497{
1498 COWDisk_Header Header;
1499 uint64_t cSectorsPerGDE;
1500
1501 int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
1502 AssertRC(rc);
1503 if (VBOX_FAILURE(rc))
1504 goto out;
1505 if ( RT_LE2H_U32(Header.magicNumber) != VMDK_ESX_SPARSE_MAGICNUMBER
1506 || RT_LE2H_U32(Header.version) != 1
1507 || RT_LE2H_U32(Header.flags) != 3)
1508 {
1509 rc = VERR_VDI_INVALID_HEADER;
1510 goto out;
1511 }
1512 pExtent->enmType = VMDKETYPE_ESX_SPARSE;
1513 pExtent->cSectors = RT_LE2H_U32(Header.numSectors);
1514 pExtent->cSectorsPerGrain = RT_LE2H_U32(Header.grainSize);
1515 /* The spec says that this must be between 1 sector and 1MB. This code
1516 * assumes it's a power of two, so check that requirement, too. */
1517 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))
1518 || pExtent->cSectorsPerGrain == 0
1519 || pExtent->cSectorsPerGrain > 2048)
1520 {
1521 rc = VERR_VDI_INVALID_HEADER;
1522 goto out;
1523 }
1524 pExtent->uDescriptorSector = 0;
1525 pExtent->cDescriptorSectors = 0;
1526 pExtent->uSectorGD = RT_LE2H_U32(Header.gdOffset);
1527 pExtent->uSectorRGD = 0;
1528 pExtent->cOverheadSectors = 0;
1529 pExtent->cGTEntries = 4096;
1530 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
1531 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
1532 {
1533 rc = VERR_VDI_INVALID_HEADER;
1534 goto out;
1535 }
1536 pExtent->cSectorsPerGDE = cSectorsPerGDE;
1537 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
1538 if (pExtent->cGDEntries != RT_LE2H_U32(Header.numGDEntries))
1539 {
1540 /* Inconsistency detected. Computed number of GD entries doesn't match
1541 * stored value. Better be safe than sorry. */
1542 rc = VERR_VDI_INVALID_HEADER;
1543 goto out;
1544 }
1545 pExtent->uFreeSector = RT_LE2H_U32(Header.freeSector);
1546 pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
1547
1548 rc = vmdkReadGrainDirectory(pExtent);
1549
1550out:
1551 if (VBOX_FAILURE(rc))
1552 vmdkFreeExtentData(pExtent, false);
1553
1554 return rc;
1555}
1556#endif /* VBOX_WITH_VMDK_ESX */
1557
1558static void vmdkFreeExtentData(PVMDKEXTENT pExtent, bool fDelete)
1559{
1560 vmdkFreeGrainDirectory(pExtent);
1561 if (pExtent->pDescData)
1562 {
1563 RTMemFree(pExtent->pDescData);
1564 pExtent->pDescData = NULL;
1565 }
1566 if (pExtent->File != NIL_RTFILE)
1567 {
1568 RTFileClose(pExtent->File);
1569 pExtent->File = NIL_RTFILE;
1570 if ( fDelete
1571 && strcmp(pExtent->pszFullname, pExtent->pszBasename) != 0
1572 && pExtent->pszFullname)
1573 RTFileDelete(pExtent->pszFullname);
1574 }
1575 if (pExtent->pszFullname)
1576 {
1577 RTStrFree((char *)(void *)pExtent->pszFullname);
1578 pExtent->pszFullname = NULL;
1579 }
1580}
1581
1582static int vmdkAllocateGrainTableCache(PVMDKIMAGE pImage)
1583{
1584 PVMDKEXTENT pExtent;
1585
1586 /* Allocate grain table cache if any sparse extent is present. */
1587 for (unsigned i = 0; i < pImage->cExtents; i++)
1588 {
1589 pExtent = &pImage->pExtents[i];
1590 if ( pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
1591#ifdef VBOX_WITH_VMDK_ESX
1592 || pExtent->enmType == VMDKETYPE_ESX_SPARSE
1593#endif /* VBOX_WITH_VMDK_ESX */
1594 )
1595 {
1596 /* Allocate grain table cache. */
1597 pImage->pGTCache = (PVMDKGTCACHE)RTMemAllocZ(sizeof(VMDKGTCACHE));
1598 if (!pImage->pGTCache)
1599 return VERR_NO_MEMORY;
1600 for (unsigned i = 0; i < VMDK_GT_CACHE_SIZE; i++)
1601 {
1602 PVMDKGTCACHEENTRY pGCE = &pImage->pGTCache->aGTCache[i];
1603 pGCE->uExtent = UINT32_MAX;
1604 }
1605 pImage->pGTCache->cEntries = VMDK_GT_CACHE_SIZE;
1606 break;
1607 }
1608 }
1609
1610 return VINF_SUCCESS;
1611}
1612static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents)
1613{
1614 int rc = VINF_SUCCESS;
1615 PVMDKEXTENT pExtents = (PVMDKEXTENT)RTMemAllocZ(cExtents * sizeof(VMDKEXTENT));
1616 if (pImage)
1617 {
1618 for (unsigned i = 0; i < cExtents; i++)
1619 {
1620 pExtents[i].File = NIL_RTFILE;
1621 pExtents[i].pszBasename = NULL;
1622 pExtents[i].pszFullname = NULL;
1623 pExtents[i].pGD = NULL;
1624 pExtents[i].pRGD = NULL;
1625 pExtents[i].pDescData = NULL;
1626 pExtents[i].uExtent = i;
1627 pExtents[i].pImage = pImage;
1628 }
1629 pImage->pExtents = pExtents;
1630 pImage->cExtents = cExtents;
1631 }
1632 else
1633 rc = VERR_NO_MEMORY;
1634
1635 return rc;
1636}
1637
1638static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename, unsigned uOpenFlags)
1639{
1640 int rc = VINF_SUCCESS;
1641 uint32_t u32Magic;
1642 RTFILE File;
1643 PVMDKEXTENT pExtent;
1644
1645 pImage->uOpenFlags = uOpenFlags;
1646
1647 /** @todo check whether the same file is used somewhere else. don't open any file twice, leads to locking problems and can cause trouble with file caching. */
1648
1649 /*
1650 * Open the image.
1651 */
1652 rc = RTFileOpen(&File, pszFilename, uOpenFlags & VD_OPEN_FLAGS_READONLY
1653 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
1654 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1655 if (VBOX_FAILURE(rc))
1656 {
1657 /* Do NOT signal an appropriate error here, as the VD layer has the
1658 * choice of retrying the open if it failed. */
1659 goto out;
1660 }
1661 pImage->File = File;
1662 rc = RTFileReadAt(File, 0, &u32Magic, sizeof(u32Magic), NULL);
1663 AssertRC(rc);
1664 if (VBOX_FAILURE(rc))
1665 {
1666 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading the magic number in '%s'"), pszFilename);
1667 goto out;
1668 }
1669
1670 /** @todo set up pImage->uImageFlags accordingly somewhere during open. */
1671
1672 /* Handle the file according to its magic number. */
1673 if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER)
1674 {
1675 /* It's a hosted sparse single-extent image. */
1676 rc = vmdkCreateExtents(pImage, 1);
1677 if (VBOX_FAILURE(rc))
1678 goto out;
1679 /* The opened file is passed to the extent. No separate descriptor
1680 * file, so no need to keep anything open for the image. */
1681 pExtent = &pImage->pExtents[0];
1682 pExtent->File = File;
1683 pImage->File = NIL_RTFILE;
1684 rc = vmdkReadMetaSparseExtent(pExtent);
1685 if (VBOX_FAILURE(rc))
1686 goto out;
1687 /* As we're dealing with a monolithic sparse image here, there must
1688 * be a descriptor embedded in the image file. */
1689 if (!pExtent->uDescriptorSector || !pExtent->cDescriptorSectors)
1690 {
1691 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image without descriptor in '%s'"), pszFilename);
1692 goto out;
1693 }
1694 /* Read the descriptor from the extent. */
1695 pExtent->pDescData = (char *)RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
1696 if (!pExtent->pDescData)
1697 {
1698 rc = VERR_NO_MEMORY;
1699 goto out;
1700 }
1701 rc = RTFileReadAt(pExtent->File,
1702 VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
1703 pExtent->pDescData,
1704 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);
1705 AssertRC(rc);
1706 if (VBOX_FAILURE(rc))
1707 {
1708 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pExtent->pszFullname);
1709 goto out;
1710 }
1711
1712 rc = vmdkParseDescriptor(pImage, pExtent->pDescData,
1713 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
1714 if (VBOX_FAILURE(rc))
1715 goto out;
1716
1717 /* Mark the extent as unclean if opened in read-write mode. */
1718 if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
1719 {
1720 pExtent->fUncleanShutdown = true;
1721 pExtent->fMetaDirty = true;
1722 }
1723 }
1724 else
1725 {
1726 pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
1727 pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
1728 if (!pImage->pDescData)
1729 {
1730 rc = VERR_NO_MEMORY;
1731 goto out;
1732 }
1733
1734 /*size_t*/unsigned cbRead;
1735 rc = RTFileReadAt(pImage->File, 0, pImage->pDescData,
1736 pImage->cbDescAlloc, &cbRead);
1737 if (VBOX_FAILURE(rc))
1738 {
1739 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pszFilename);
1740 goto out;
1741 }
1742 if (cbRead == pImage->cbDescAlloc)
1743 {
1744 /* Likely the read is truncated. Better fail a bit too early
1745 * (normally the descriptor is much smaller than our buffer). */
1746 rc = vmdkError(pImage, VERR_VDI_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot read descriptor in '%s'"), pszFilename);
1747 goto out;
1748 }
1749
1750 rc = vmdkParseDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc);
1751 if (VBOX_FAILURE(rc))
1752 goto out;
1753
1754 for (unsigned i = 0; i < pImage->cExtents; i++)
1755 {
1756 PVMDKEXTENT pExtent = &pImage->pExtents[i];
1757
1758 if (pExtent->pszBasename)
1759 {
1760 /* Hack to figure out whether the specified name in the
1761 * extent descriptor is absolute. Doesn't always work, but
1762 * should be good enough for now. */
1763 /** @todo implement proper path absolute check. */
1764 if (pExtent->pszBasename[0] == RTPATH_SLASH)
1765 {
1766 pszFilename = RTStrDup(pExtent->pszBasename);
1767 if (!pszFilename)
1768 {
1769 rc = VERR_NO_MEMORY;
1770 goto out;
1771 }
1772 }
1773 else
1774 {
1775 size_t cbDirname;
1776 char *pszDirname = RTStrDup(pImage->pszFilename);
1777 if (!pszDirname)
1778 {
1779 rc = VERR_NO_MEMORY;
1780 goto out;
1781 }
1782 RTPathStripFilename(pszDirname);
1783 cbDirname = strlen(pszDirname);
1784 char *pszFullname;
1785 rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname,
1786 RTPATH_SLASH, pExtent->pszBasename);
1787 RTStrFree(pszDirname);
1788 if (VBOX_FAILURE(rc))
1789 goto out;
1790 pExtent->pszFullname = pszFullname;
1791 }
1792 }
1793 else
1794 pExtent->pszFullname = NULL;
1795
1796 switch (pExtent->enmType)
1797 {
1798 case VMDKETYPE_HOSTED_SPARSE:
1799 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
1800 uOpenFlags & VD_OPEN_FLAGS_READONLY
1801 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
1802 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1803 if (VBOX_FAILURE(rc))
1804 {
1805 /* Do NOT signal an appropriate error here, as the VD
1806 * layer has the choice of retrying the open if it
1807 * failed. */
1808 goto out;
1809 }
1810 rc = vmdkReadMetaSparseExtent(pExtent);
1811 if (VBOX_FAILURE(rc))
1812 goto out;
1813
1814 /* Mark the extent as unclean if opened in read-write mode. */
1815 if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
1816 {
1817 pExtent->fUncleanShutdown = true;
1818 pExtent->fMetaDirty = true;
1819 }
1820 break;
1821 case VMDKETYPE_FLAT:
1822 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
1823 uOpenFlags & VD_OPEN_FLAGS_READONLY
1824 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
1825 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1826 if (VBOX_FAILURE(rc))
1827 {
1828 /* Do NOT signal an appropriate error here, as the VD
1829 * layer has the choice of retrying the open if it
1830 * failed. */
1831 goto out;
1832 }
1833 break;
1834 case VMDKETYPE_ZERO:
1835 /* Nothing to do. */
1836 break;
1837 default:
1838 AssertMsgFailed(("unknown vmdk extent type %d\n", pExtent->enmType));
1839 }
1840 }
1841 }
1842
1843 /* Make sure this is not reached accidentally with an error status. */
1844 AssertRC(rc);
1845
1846 /* Update the image metadata now in case has changed. */
1847 rc = vmdkFlushImage(pImage);
1848 if (VBOX_FAILURE(rc))
1849 goto out;
1850
1851 /* Figure out a few per-image constants from the extents. */
1852 pImage->cbSize = 0;
1853 for (unsigned i = 0; i < pImage->cExtents; i++)
1854 {
1855 pExtent = &pImage->pExtents[i];
1856 if ( pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
1857#ifdef VBOX_WITH_VMDK_ESX
1858 || pExtent->enmType == VMDKETYPE_ESX_SPARSE
1859#endif /* VBOX_WITH_VMDK_ESX */
1860 )
1861 {
1862 /* Here used to be a check whether the nominal size of an extent
1863 * is a multiple of the grain size. The spec says that this is
1864 * always the case, but unfortunately some files out there in the
1865 * wild violate the spec (e.g. ReactOS 0.3.1). */
1866 }
1867 pImage->cbSize += VMDK_SECTOR2BYTE(pExtent->cNominalSectors);
1868 }
1869
1870 pImage->enmImageType = VD_IMAGE_TYPE_NORMAL;
1871 for (unsigned i = 0; i < pImage->cExtents; i++)
1872 {
1873 pExtent = &pImage->pExtents[i];
1874 if ( pImage->pExtents[i].enmType == VMDKETYPE_FLAT
1875 || pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
1876 {
1877 pImage->enmImageType = VD_IMAGE_TYPE_FIXED;
1878 break;
1879 }
1880 }
1881
1882 rc = vmdkAllocateGrainTableCache(pImage);
1883 if (VBOX_FAILURE(rc))
1884 goto out;
1885
1886out:
1887 if (VBOX_FAILURE(rc))
1888 vmdkFreeImage(pImage, false);
1889 return rc;
1890}
1891
1892static int vmdkCreateImage(PVMDKIMAGE pImage, const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
1893{
1894 int rc;
1895 uint64_t cSectorsPerGDE, cSectorsPerGD;
1896 PVMDKEXTENT pExtent;
1897
1898 pImage->uImageFlags = uImageFlags;
1899 rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc, &pImage->Descriptor);
1900 if (VBOX_FAILURE(rc))
1901 {
1902 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename);
1903 goto out;
1904 }
1905
1906 if ( enmType == VD_IMAGE_TYPE_FIXED
1907 || (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
1908 || (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
1909 {
1910 /* Fixed images and split images in general have a separate descriptor
1911 * file. This is the more complicated case, as it requires setting up
1912 * potentially more than one extent, including filename generation. */
1913
1914 if ( enmType == VD_IMAGE_TYPE_FIXED
1915 && (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
1916 {
1917 PVBOXHDDRAW pRaw = (PVBOXHDDRAW)(void *)pszComment;
1918 if (pRaw->fRawDisk)
1919 {
1920 /* Full raw disk access. This requires setting up a descriptor
1921 * file and open the (flat) raw disk. */
1922 rc = vmdkCreateExtents(pImage, 1);
1923 if (VBOX_FAILURE(rc))
1924 {
1925 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
1926 goto out;
1927 }
1928 pExtent = &pImage->pExtents[0];
1929 rc = RTFileOpen(&pImage->File, pszFilename,
1930 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
1931 if (VBOX_FAILURE(rc))
1932 {
1933 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
1934 goto out;
1935 }
1936
1937 /* Set up basename for extent description. Cannot use StrDup. */
1938 size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
1939 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
1940 if (!pszBasename)
1941 {
1942 rc = VERR_NO_MEMORY;
1943 goto out;
1944 }
1945 memcpy(pszBasename, pRaw->pszRawDisk, cbBasename);
1946 pExtent->pszBasename = pszBasename;
1947 /* For raw disks the full name is identical to the base name. */
1948 pExtent->pszFullname = RTStrDup(pszBasename);
1949 if (!pExtent->pszFullname)
1950 {
1951 rc = VERR_NO_MEMORY;
1952 goto out;
1953 }
1954 pExtent->enmType = VMDKETYPE_FLAT;
1955 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
1956 pExtent->uSectorOffset = 0;
1957 pExtent->enmAccess = VMDKACCESS_READWRITE;
1958 pExtent->fMetaDirty = true;
1959
1960 pImage->enmImageType = enmType;
1961 rc = vmdkDescSetStr(pImage, &pImage->Descriptor, pImage->Descriptor.uFirstDesc, "createType", "\"fullDevice\"");
1962 if (VBOX_FAILURE(rc))
1963 {
1964 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
1965 goto out;
1966 }
1967
1968 /* Open flat image, the raw disk. */
1969 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
1970 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1971 if (VBOX_FAILURE(rc))
1972 {
1973 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
1974 goto out;
1975 }
1976 }
1977 else
1978 {
1979 /******* fixme. */
1980 rc = VERR_NOT_IMPLEMENTED;
1981 goto out;
1982 }
1983 }
1984 else
1985 {
1986 rc = VERR_NOT_IMPLEMENTED;
1987 goto out;
1988 }
1989 }
1990 else
1991 {
1992 /* Normal (growing) image which is not split into pieces. */
1993 rc = vmdkCreateExtents(pImage, 1);
1994 if (VBOX_FAILURE(rc))
1995 {
1996 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
1997 goto out;
1998 }
1999 pExtent = &pImage->pExtents[0];
2000 pImage->File = NIL_RTFILE;
2001 rc = RTFileOpen(&pExtent->File, pszFilename,
2002 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
2003 if (VBOX_FAILURE(rc))
2004 {
2005 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
2006 goto out;
2007 }
2008
2009 /* Set up basename for extent description. Cannot use StrDup, as it is
2010 * not guaranteed that the memory can be freed with RTMemTmpFree, which
2011 * must be used as in other code paths StrDup is not usable. */
2012 char *pszBasenameSubstr = RTPathFilename(pszFilename);
2013 Assert(pszBasenameSubstr);
2014 size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
2015 char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
2016 if (!pszBasename)
2017 {
2018 rc = VERR_NO_MEMORY;
2019 goto out;
2020 }
2021 memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
2022 pExtent->pszBasename = pszBasename;
2023 pExtent->pszFullname = RTStrDup(pszFilename);
2024 if (!pExtent->pszFullname)
2025 {
2026 rc = VERR_NO_MEMORY;
2027 goto out;
2028 }
2029 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
2030 pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, 65536));
2031 pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536);
2032 pExtent->uDescriptorSector = 1;
2033 pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
2034 pExtent->cGTEntries = 512;
2035 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
2036 pExtent->cSectorsPerGDE = cSectorsPerGDE;
2037 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
2038 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
2039 pExtent->enmAccess = VMDKACCESS_READWRITE;
2040 pExtent->fUncleanShutdown = true;
2041 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
2042 pExtent->uSectorOffset = 0;
2043 pExtent->fMetaDirty = true;
2044
2045 rc = vmdkCreateGrainDirectory(pExtent, pExtent->uDescriptorSector + pExtent->cDescriptorSectors, true);
2046 if (VBOX_FAILURE(rc))
2047 {
2048 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pszFilename);
2049 goto out;
2050 }
2051
2052 pImage->enmImageType = enmType;
2053 rc = vmdkDescSetStr(pImage, &pImage->Descriptor, pImage->Descriptor.uFirstDesc, "createType", "\"monolithicSparse\"");
2054 if (VBOX_FAILURE(rc))
2055 {
2056 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
2057 goto out;
2058 }
2059
2060 /* The descriptor is part of the extent, move info to extent. */
2061 pExtent->pDescData = pImage->pDescData;
2062 pImage->pDescData = NULL;
2063 }
2064
2065 pImage->cbSize = cbSize;
2066 if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
2067 pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
2068 else
2069 pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;
2070
2071 for (unsigned i = 0; i < pImage->cExtents; i++)
2072 {
2073 pExtent = &pImage->pExtents[i];
2074
2075 rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
2076 pExtent->cNominalSectors, pExtent->enmType,
2077 pExtent->pszBasename, pExtent->uSectorOffset);
2078 if (VBOX_FAILURE(rc))
2079 {
2080 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pszFilename);
2081 goto out;
2082 }
2083 }
2084 vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
2085
2086 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2087 "ddb.geometry.cylinders", cCylinders);
2088 if (VBOX_FAILURE(rc))
2089 goto out;
2090 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2091 "ddb.geometry.heads", cHeads);
2092 if (VBOX_FAILURE(rc))
2093 goto out;
2094 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2095 "ddb.geometry.sectors", cSectors);
2096 if (VBOX_FAILURE(rc))
2097 goto out;
2098
2099 pImage->cCylinders = cCylinders;
2100 pImage->cHeads = cHeads;
2101 pImage->cSectors = cSectors;
2102
2103 rc = RTUuidCreate(&pImage->ImageUuid);
2104 if (VBOX_FAILURE(rc))
2105 goto out;
2106 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2107 "ddb.uuid.image", &pImage->ImageUuid);
2108 if (VBOX_FAILURE(rc))
2109 {
2110 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pszFilename);
2111 goto out;
2112 }
2113 RTUuidClear(&pImage->ParentUuid);
2114 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2115 "ddb.uuid.parent", &pImage->ParentUuid);
2116 if (VBOX_FAILURE(rc))
2117 {
2118 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pszFilename);
2119 goto out;
2120 }
2121 RTUuidClear(&pImage->ModificationUuid);
2122 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2123 "ddb.uuid.modification", &pImage->ModificationUuid);
2124 if (VBOX_FAILURE(rc))
2125 {
2126 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pszFilename);
2127 goto out;
2128 }
2129
2130 rc = vmdkAllocateGrainTableCache(pImage);
2131 if (VBOX_FAILURE(rc))
2132 goto out;
2133
2134 rc = vmdkFlushImage(pImage);
2135
2136out:
2137 if (VBOX_FAILURE(rc))
2138 vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
2139 return rc;
2140}
2141
2142static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete)
2143{
2144 if (pImage->enmImageType)
2145 {
2146 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2147 {
2148 /* Mark all extents as clean. */
2149 for (unsigned i = 0; i < pImage->cExtents; i++)
2150 {
2151 if (( pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
2152#ifdef VBOX_WITH_VMDK_ESX
2153 || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
2154#endif /* VBOX_WITH_VMDK_ESX */
2155 )
2156 && pImage->pExtents[i].fUncleanShutdown)
2157 {
2158 pImage->pExtents[i].fUncleanShutdown = false;
2159 pImage->pExtents[i].fMetaDirty = true;
2160 }
2161 }
2162 }
2163 (void)vmdkFlushImage(pImage);
2164 }
2165 if (pImage->pExtents != NULL)
2166 {
2167 for (unsigned i = 0 ; i < pImage->cExtents; i++)
2168 vmdkFreeExtentData(&pImage->pExtents[i], fDelete);
2169 RTMemFree(pImage->pExtents);
2170 pImage->pExtents = NULL;
2171 }
2172 if (pImage->File != NIL_RTFILE)
2173 {
2174 RTFileClose(pImage->File);
2175 pImage->File = NIL_RTFILE;
2176 }
2177 if (fDelete && pImage->pszFilename)
2178 RTFileDelete(pImage->pszFilename);
2179}
2180
2181static int vmdkFlushImage(PVMDKIMAGE pImage)
2182{
2183 PVMDKEXTENT pExtent;
2184 int rc = VINF_SUCCESS;
2185
2186 /* Update descriptor if changed. */
2187 if (pImage->Descriptor.fDirty)
2188 {
2189 rc = vmdkWriteDescriptor(pImage);
2190 if (VBOX_FAILURE(rc))
2191 goto out;
2192 }
2193
2194 for (unsigned i = 0; i < pImage->cExtents; i++)
2195 {
2196 pExtent = &pImage->pExtents[i];
2197 if (pExtent->File != NIL_RTFILE && pExtent->fMetaDirty)
2198 {
2199 switch (pExtent->enmType)
2200 {
2201 case VMDKETYPE_HOSTED_SPARSE:
2202 rc = vmdkWriteMetaSparseExtent(pExtent);
2203 if (VBOX_FAILURE(rc))
2204 goto out;
2205 break;
2206#ifdef VBOX_WITH_VMDK_ESX
2207 case VMDKETYPE_ESX_SPARSE:
2208 /** @todo update the header. */
2209 break;
2210#endif /* VBOX_WITH_VMDK_ESX */
2211 case VMDKETYPE_FLAT:
2212 /* Nothing to do. */
2213 break;
2214 case VMDKETYPE_ZERO:
2215 default:
2216 AssertMsgFailed(("extent with type %d marked as dirty\n",
2217 pExtent->enmType));
2218 break;
2219 }
2220 }
2221 switch (pExtent->enmType)
2222 {
2223 case VMDKETYPE_HOSTED_SPARSE:
2224#ifdef VBOX_WITH_VMDK_ESX
2225 case VMDKETYPE_ESX_SPARSE:
2226#endif /* VBOX_WITH_VMDK_ESX */
2227 case VMDKETYPE_FLAT:
2228 if (pExtent->File != NIL_RTFILE && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2229 rc = RTFileFlush(pExtent->File);
2230 break;
2231 case VMDKETYPE_ZERO:
2232 /* No need to do anything for this extent. */
2233 break;
2234 default:
2235 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
2236 break;
2237 }
2238 }
2239
2240out:
2241 return rc;
2242}
2243
2244static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector, PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
2245{
2246 PVMDKEXTENT pExtent = NULL;
2247 int rc = VINF_SUCCESS;
2248
2249 for (unsigned i = 0; i < pImage->cExtents; i++)
2250 {
2251 if (offSector < pImage->pExtents[i].cNominalSectors)
2252 {
2253 pExtent = &pImage->pExtents[i];
2254 *puSectorInExtent = offSector + pImage->pExtents[i].uSectorOffset;
2255 break;
2256 }
2257 offSector -= pImage->pExtents[i].cNominalSectors;
2258 }
2259
2260 if (pExtent)
2261 *ppExtent = pExtent;
2262 else
2263 rc = VERR_IO_SECTOR_NOT_FOUND;
2264
2265 return rc;
2266}
2267
2268static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector, unsigned uExtent)
2269{
2270 /** @todo this hash function is quite simple, maybe use a better one which
2271 * scrambles the bits better. */
2272 return (uSector + uExtent) % pCache->cEntries;
2273}
2274
2275static int vmdkGetSector(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
2276 uint64_t uSector, uint64_t *puExtentSector)
2277{
2278 uint64_t uGDIndex, uGTSector, uGTBlock;
2279 uint32_t uGTHash, uGTBlockIndex;
2280 PVMDKGTCACHEENTRY pGTCacheEntry;
2281 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
2282 int rc;
2283
2284 uGDIndex = uSector / pExtent->cSectorsPerGDE;
2285 if (uGDIndex >= pExtent->cGDEntries)
2286 return VERR_OUT_OF_RANGE;
2287 uGTSector = pExtent->pGD[uGDIndex];
2288 if (!uGTSector)
2289 {
2290 /* There is no grain table referenced by this grain directory
2291 * entry. So there is absolutely no data in this area. */
2292 *puExtentSector = 0;
2293 return VINF_SUCCESS;
2294 }
2295
2296 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
2297 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
2298 pGTCacheEntry = &pCache->aGTCache[uGTHash];
2299 if ( pGTCacheEntry->uExtent != pExtent->uExtent
2300 || pGTCacheEntry->uGTBlock != uGTBlock)
2301 {
2302 /* Cache miss, fetch data from disk. */
2303 rc = RTFileReadAt(pExtent->File,
2304 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
2305 aGTDataTmp, sizeof(aGTDataTmp), NULL);
2306 if (VBOX_FAILURE(rc))
2307 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
2308 pGTCacheEntry->uExtent = pExtent->uExtent;
2309 pGTCacheEntry->uGTBlock = uGTBlock;
2310 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
2311 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
2312 }
2313 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
2314 uint64_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
2315 if (uGrainSector)
2316 *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
2317 else
2318 *puExtentSector = 0;
2319 return VINF_SUCCESS;
2320}
2321
2322/**
2323 * Internal. Allocates a new grain table (if necessary), writes the grain
2324 * and updates the grain table. The cache is also updated by this operation.
2325 * This is separate from vmdkGetSector, because that should be as fast as
2326 * possible. Most code from vmdkGetSector also appears here.
2327 */
2328static int vmdkAllocGrain(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
2329 uint64_t uSector, const void *pvBuf, uint64_t cbWrite)
2330{
2331 uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
2332 uint64_t cbExtentSize;
2333 uint32_t uGTHash, uGTBlockIndex;
2334 PVMDKGTCACHEENTRY pGTCacheEntry;
2335 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
2336 int rc;
2337
2338 uGDIndex = uSector / pExtent->cSectorsPerGDE;
2339 if (uGDIndex >= pExtent->cGDEntries)
2340 return VERR_OUT_OF_RANGE;
2341 uGTSector = pExtent->pGD[uGDIndex];
2342 uRGTSector = pExtent->pRGD[uGDIndex];
2343 if (!uGTSector)
2344 {
2345 /* There is no grain table referenced by this grain directory
2346 * entry. So there is absolutely no data in this area. Allocate
2347 * a new grain table and put the reference to it in the GDs. */
2348 rc = RTFileGetSize(pExtent->File, &cbExtentSize);
2349 if (VBOX_FAILURE(rc))
2350 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
2351 Assert(!(cbExtentSize % 512));
2352 uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
2353 /* Normally the grain table is preallocated for hosted sparse extents
2354 * that support more than 32 bit sector numbers. So this shouldn't
2355 * ever happen on a valid extent. */
2356 if (uGTSector > UINT32_MAX)
2357 return VERR_VDI_INVALID_HEADER;
2358 /* Write grain table by writing the required number of grain table
2359 * cache chunks. Avoids dynamic memory allocation, but is a bit
2360 * slower. But as this is a pretty infrequently occurring case it
2361 * should be acceptable. */
2362 memset(aGTDataTmp, '\0', sizeof(aGTDataTmp));
2363 for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++)
2364 {
2365 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
2366 if (VBOX_FAILURE(rc))
2367 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
2368 }
2369 if (pExtent->pRGD)
2370 {
2371 rc = RTFileGetSize(pExtent->File, &cbExtentSize);
2372 if (VBOX_FAILURE(rc))
2373 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
2374 Assert(!(cbExtentSize % 512));
2375 uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
2376 /* Write backup grain table by writing the required number of grain
2377 * table cache chunks. Avoids dynamic memory allocation, but is a
2378 * bit slower. But as this is a pretty infrequently occurring case
2379 * it should be acceptable. */
2380 for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++)
2381 {
2382 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
2383 if (VBOX_FAILURE(rc))
2384 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
2385 }
2386 }
2387
2388 /* Update the grain directory on disk (doing it before writing the
2389 * grain table will result in a garbled extent if the operation is
2390 * aborted for some reason. Otherwise the worst that can happen is
2391 * some unused sectors in the extent. */
2392 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
2393 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
2394 if (VBOX_FAILURE(rc))
2395 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
2396 if (pExtent->pRGD)
2397 {
2398 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
2399 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE), &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
2400 if (VBOX_FAILURE(rc))
2401 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
2402 }
2403
2404 /* As the final step update the in-memory copy of the GDs. */
2405 pExtent->pGD[uGDIndex] = uGTSector;
2406 if (pExtent->pRGD)
2407 pExtent->pRGD[uGDIndex] = uRGTSector;
2408 }
2409
2410 rc = RTFileGetSize(pExtent->File, &cbExtentSize);
2411 if (VBOX_FAILURE(rc))
2412 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
2413 Assert(!(cbExtentSize % 512));
2414
2415 /* Write the data. */
2416 rc = RTFileWriteAt(pExtent->File, cbExtentSize, pvBuf, cbWrite, NULL);
2417 if (VBOX_FAILURE(rc))
2418 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
2419
2420 /* Update the grain table (and the cache). */
2421 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
2422 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
2423 pGTCacheEntry = &pCache->aGTCache[uGTHash];
2424 if ( pGTCacheEntry->uExtent != pExtent->uExtent
2425 || pGTCacheEntry->uGTBlock != uGTBlock)
2426 {
2427 /* Cache miss, fetch data from disk. */
2428 rc = RTFileReadAt(pExtent->File,
2429 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
2430 aGTDataTmp, sizeof(aGTDataTmp), NULL);
2431 if (VBOX_FAILURE(rc))
2432 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
2433 pGTCacheEntry->uExtent = pExtent->uExtent;
2434 pGTCacheEntry->uGTBlock = uGTBlock;
2435 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
2436 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
2437 }
2438 else
2439 {
2440 /* Cache hit. Convert grain table block back to disk format, otherwise
2441 * the code below will write garbage for all but the updated entry. */
2442 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
2443 aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
2444 }
2445 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
2446 aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(cbExtentSize));
2447 pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(cbExtentSize);
2448 /* Update grain table on disk. */
2449 rc = RTFileWriteAt(pExtent->File,
2450 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
2451 aGTDataTmp, sizeof(aGTDataTmp), NULL);
2452 if (VBOX_FAILURE(rc))
2453 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
2454 if (pExtent->pRGD)
2455 {
2456 /* Update backup grain table on disk. */
2457 rc = RTFileWriteAt(pExtent->File,
2458 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
2459 aGTDataTmp, sizeof(aGTDataTmp), NULL);
2460 if (VBOX_FAILURE(rc))
2461 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
2462 }
2463#ifdef VBOX_WITH_VMDK_ESX
2464 if (VBOX_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
2465 {
2466 pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
2467 pExtent->fMetaDirty = true;
2468 }
2469#endif /* VBOX_WITH_VMDK_ESX */
2470 return rc;
2471}
2472
2473static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData)
2474{
2475 int rc;
2476 PVMDKIMAGE pImage;
2477
2478 /** @todo check the image file name for invalid characters, especially double quotes. */
2479
2480 /* Check open flags. All valid flags are supported. */
2481 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
2482 {
2483 rc = VERR_INVALID_PARAMETER;
2484 goto out;
2485 }
2486
2487 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
2488 if (!pImage)
2489 {
2490 rc = VERR_NO_MEMORY;
2491 goto out;
2492 }
2493 pImage->pszFilename = pszFilename;
2494 pImage->File = NIL_RTFILE;
2495 pImage->pExtents = NULL;
2496 pImage->pGTCache = NULL;
2497 pImage->pDescData = NULL;
2498 pImage->pfnError = pfnError;
2499 pImage->pvErrorUser = pvErrorUser;
2500
2501 rc = vmdkOpenImage(pImage, pszFilename, uOpenFlags);
2502 if (VBOX_SUCCESS(rc))
2503 *ppvBackendData = pImage;
2504
2505out:
2506 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
2507 return rc;
2508}
2509
2510static int vmdkCreate(const char *pszFilename, VDIMAGETYPE enmType,
2511 uint64_t cbSize, unsigned uImageFlags,
2512 const char *pszComment, uint32_t cCylinders,
2513 uint32_t cHeads, uint32_t cSectors, unsigned uOpenFlags,
2514 PFNVMPROGRESS pfnProgress, void *pvUser,
2515 PFNVDERROR pfnError, void *pvErrorUser,
2516 void **ppvBackendData)
2517{
2518 int rc;
2519 PVMDKIMAGE pImage;
2520
2521 /** @todo check the image file name for invalid characters, especially double quotes. */
2522
2523 /* Check open flags. All valid flags are supported. */
2524 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
2525 {
2526 rc = VERR_INVALID_PARAMETER;
2527 goto out;
2528 }
2529
2530 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
2531 if (!pImage)
2532 {
2533 rc = VERR_NO_MEMORY;
2534 goto out;
2535 }
2536 pImage->pszFilename = pszFilename;
2537 pImage->File = NIL_RTFILE;
2538 pImage->pExtents = NULL;
2539 pImage->pGTCache = NULL;
2540 pImage->pDescData = NULL;
2541 pImage->pfnError = pfnError;
2542 pImage->pvErrorUser = pvErrorUser;
2543 pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
2544 pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
2545 if (!pImage->pDescData)
2546 {
2547 rc = VERR_NO_MEMORY;
2548 goto out;
2549 }
2550
2551 rc = vmdkCreateImage(pImage, pszFilename, enmType, cbSize, uImageFlags,
2552 pszComment, cCylinders, cHeads, cSectors);
2553 if (VBOX_SUCCESS(rc))
2554 {
2555 /* So far the image is opened in read/write mode. Make sure the
2556 * image is opened in read-only mode if the caller requested that. */
2557 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
2558 {
2559 vmdkFreeImage(pImage, false);
2560 rc = vmdkOpenImage(pImage, pszFilename, uOpenFlags);
2561 if (VBOX_FAILURE(rc))
2562 goto out;
2563 }
2564 *ppvBackendData = pImage;
2565 }
2566
2567out:
2568 /** @todo implement meaningful progress stuff (especially for fixed images). */
2569 if ( VBOX_SUCCESS(rc)
2570 && pfnProgress)
2571 pfnProgress(NULL /* WARNING! pVM=NULL */, 100, pvUser);
2572
2573 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
2574 return rc;
2575}
2576
2577static int vmdkClose(void *pBackendData, bool fDelete)
2578{
2579 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2580 int rc = VINF_SUCCESS;
2581
2582 /* Freeing a never allocated image (e.g. because the open failed) is
2583 * not signalled as an error. After all nothing bad happens. */
2584 if (pImage)
2585 vmdkFreeImage(pImage, fDelete);
2586
2587 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
2588 return rc;
2589}
2590
2591static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf, size_t cbRead, size_t *pcbActuallyRead)
2592{
2593 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2594 PVMDKEXTENT pExtent;
2595 uint64_t uSectorExtentRel;
2596 uint64_t uSectorExtentAbs;
2597 int rc;
2598
2599 Assert(uOffset % 512 == 0);
2600 Assert(cbRead % 512 == 0);
2601
2602 if (uOffset + cbRead > pImage->cbSize)
2603 {
2604 rc = VERR_INVALID_PARAMETER;
2605 goto out;
2606 }
2607
2608 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
2609 &pExtent, &uSectorExtentRel);
2610 if (VBOX_FAILURE(rc))
2611 goto out;
2612
2613 /* Check access permissions as defined in the extent descriptor. */
2614 if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
2615 {
2616 rc = VERR_VDI_INVALID_STATE;
2617 goto out;
2618 }
2619
2620 /* Clip read range to remain in this extent. */
2621 cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->cNominalSectors - uSectorExtentRel));
2622
2623 /* Handle the read according to the current extent type. */
2624 switch (pExtent->enmType)
2625 {
2626 case VMDKETYPE_HOSTED_SPARSE:
2627#ifdef VBOX_WITH_VMDK_ESX
2628 case VMDKETYPE_ESX_SPARSE:
2629#endif /* VBOX_WITH_VMDK_ESX */
2630 rc = vmdkGetSector(pImage->pGTCache, pExtent, uSectorExtentRel,
2631 &uSectorExtentAbs);
2632 if (VBOX_FAILURE(rc))
2633 goto out;
2634 /* Clip read range to at most the rest of the grain. */
2635 cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
2636 Assert(!(cbRead % 512));
2637 if (uSectorExtentAbs == 0)
2638 rc = VINF_VDI_BLOCK_FREE;
2639 else
2640 rc = RTFileReadAt(pExtent->File,
2641 VMDK_SECTOR2BYTE(uSectorExtentAbs),
2642 pvBuf, cbRead, NULL);
2643 break;
2644 case VMDKETYPE_FLAT:
2645 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel),
2646 pvBuf, cbRead, NULL);
2647 break;
2648 case VMDKETYPE_ZERO:
2649 memset(pvBuf, '\0', cbRead);
2650 break;
2651 }
2652 *pcbActuallyRead = cbRead;
2653
2654out:
2655 return rc;
2656}
2657
2658static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, size_t cbWrite, size_t *pcbWriteProcess, size_t *pcbPreRead, size_t *pcbPostRead)
2659{
2660 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2661 PVMDKEXTENT pExtent;
2662 uint64_t uSectorExtentRel;
2663 uint64_t uSectorExtentAbs;
2664 int rc;
2665
2666 Assert(uOffset % 512 == 0);
2667 Assert(cbWrite % 512 == 0);
2668
2669 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2670 {
2671 rc = VERR_VDI_IMAGE_READ_ONLY;
2672 goto out;
2673 }
2674
2675 /* No size check here, will do that later when the extent is located.
2676 * There are sparse images out there which according to the spec are
2677 * invalid, because the total size is not a multiple of the grain size.
2678 * Also for sparse images which are stitched together in odd ways (not at
2679 * grain boundaries, and with the nominal size not being a multiple of the
2680 * grain size), this would prevent writing to the last grain. */
2681
2682 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
2683 &pExtent, &uSectorExtentRel);
2684 if (VBOX_FAILURE(rc))
2685 goto out;
2686
2687 /* Check access permissions as defined in the extent descriptor. */
2688 if (pExtent->enmAccess != VMDKACCESS_READWRITE)
2689 {
2690 rc = VERR_VDI_INVALID_STATE;
2691 goto out;
2692 }
2693
2694 /** @todo implement suppressing of zero data writes (a bit tricky in this
2695 * case, as VMDK has no marker for zero blocks). We somehow need to get the
2696 * information whether the information in this area is all zeroes as of the
2697 * parent image. Then (based on the assumption that parent images are
2698 * immutable) the write can be ignored. */
2699
2700 /* Handle the write according to the current extent type. */
2701 switch (pExtent->enmType)
2702 {
2703 case VMDKETYPE_HOSTED_SPARSE:
2704#ifdef VBOX_WITH_VMDK_ESX
2705 case VMDKETYPE_ESX_SPARSE:
2706#endif /* VBOX_WITH_VMDK_ESX */
2707 rc = vmdkGetSector(pImage->pGTCache, pExtent, uSectorExtentRel,
2708 &uSectorExtentAbs);
2709 if (VBOX_FAILURE(rc))
2710 goto out;
2711 /* Clip write range to at most the rest of the grain. */
2712 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
2713 if (uSectorExtentAbs == 0)
2714 {
2715 if (cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
2716 {
2717 /* Full block write to a previously unallocated block.
2718 * Allocate GT and find out where to store the grain. */
2719 rc = vmdkAllocGrain(pImage->pGTCache, pExtent,
2720 uSectorExtentRel, pvBuf, cbWrite);
2721 *pcbPreRead = 0;
2722 *pcbPostRead = 0;
2723 }
2724 else
2725 {
2726 /* Clip write range to remain in this extent. */
2727 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cNominalSectors - uSectorExtentRel));
2728 *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
2729 *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite - *pcbPreRead;
2730 rc = VINF_VDI_BLOCK_FREE;
2731 }
2732 }
2733 else
2734 rc = RTFileWriteAt(pExtent->File,
2735 VMDK_SECTOR2BYTE(uSectorExtentAbs),
2736 pvBuf, cbWrite, NULL);
2737 break;
2738 case VMDKETYPE_FLAT:
2739 /* Clip write range to remain in this extent. */
2740 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cNominalSectors - uSectorExtentRel));
2741 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel), pvBuf, cbWrite, NULL);
2742 break;
2743 case VMDKETYPE_ZERO:
2744 /* Clip write range to remain in this extent. */
2745 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cNominalSectors - uSectorExtentRel));
2746 break;
2747 }
2748 if (pcbWriteProcess)
2749 *pcbWriteProcess = cbWrite;
2750
2751out:
2752 return rc;
2753}
2754
2755static int vmdkFlush(void *pBackendData)
2756{
2757 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2758
2759 int rc = vmdkFlushImage(pImage);
2760
2761 return rc;
2762}
2763
2764static int vmdkGetImageType(void *pBackendData, PVDIMAGETYPE penmImageType)
2765{
2766 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2767 int rc = VINF_SUCCESS;
2768
2769 Assert(pImage);
2770 Assert(penmImageType);
2771
2772 if (pImage && pImage->cExtents != 0)
2773 *penmImageType = pImage->enmImageType;
2774 else
2775 rc = VERR_VDI_NOT_OPENED;
2776
2777 return rc;
2778}
2779
2780static uint64_t vmdkGetSize(void *pBackendData)
2781{
2782 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2783
2784 Assert(pImage);
2785
2786 if (pImage)
2787 return pImage->cbSize;
2788 else
2789 return 0;
2790}
2791
2792static int vmdkGetGeometry(void *pBackendData, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors)
2793{
2794 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2795 int rc;
2796
2797 Assert(pImage);
2798
2799 if (pImage)
2800 {
2801 if (pImage->cCylinders)
2802 {
2803 *pcCylinders = pImage->cCylinders;
2804 *pcHeads = pImage->cHeads;
2805 *pcSectors = pImage->cSectors;
2806 rc = VINF_SUCCESS;
2807 }
2808 else
2809 rc = VERR_VDI_GEOMETRY_NOT_SET;
2810 }
2811 else
2812 rc = VERR_VDI_NOT_OPENED;
2813 LogFlow(("%s: returned %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc,
2814 pImage->cCylinders, pImage->cHeads, pImage->cSectors));
2815 return rc;
2816}
2817
2818static int vmdkSetGeometry(void *pBackendData, unsigned cCylinders, unsigned cHeads, unsigned cSectors)
2819{
2820 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2821 int rc;
2822
2823 Assert(pImage);
2824
2825 if (pImage)
2826 {
2827 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2828 {
2829 rc = VERR_VDI_IMAGE_READ_ONLY;
2830 goto out;
2831 }
2832 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2833 "ddb.geometry.cylinders", cCylinders);
2834 if (VBOX_FAILURE(rc))
2835 goto out;
2836 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2837 "ddb.geometry.heads", cHeads);
2838 if (VBOX_FAILURE(rc))
2839 goto out;
2840 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2841 "ddb.geometry.sectors", cSectors);
2842 if (VBOX_FAILURE(rc))
2843 goto out;
2844
2845 pImage->cCylinders = cCylinders;
2846 pImage->cHeads = cHeads;
2847 pImage->cSectors = cSectors;
2848 rc = VINF_SUCCESS;
2849 }
2850 else
2851 rc = VERR_VDI_NOT_OPENED;
2852
2853out:
2854 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
2855 return rc;
2856}
2857
2858static int vmdkGetTranslation(void *pBackendData, PPDMBIOSTRANSLATION penmTranslation)
2859{
2860 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2861 int rc;
2862
2863 Assert(pImage);
2864
2865 if (pImage)
2866 {
2867 if (pImage->enmTranslation)
2868 {
2869 *penmTranslation = pImage->enmTranslation;
2870 rc = VINF_SUCCESS;
2871 }
2872 else
2873 rc = VERR_VDI_GEOMETRY_NOT_SET;
2874 }
2875 else
2876 rc = VERR_VDI_NOT_OPENED;
2877 LogFlow(("%s: returned %Vrc (%d)\n", __FUNCTION__, rc,
2878 pImage->enmTranslation));
2879 return rc;
2880}
2881
2882static int vmdkSetTranslation(void *pBackendData, PDMBIOSTRANSLATION enmTranslation)
2883{
2884 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2885 int rc;
2886
2887 Assert(pImage);
2888
2889 if (pImage)
2890 {
2891 /** @todo maybe store this in the image descriptor */
2892 pImage->enmTranslation = enmTranslation;
2893 rc = VINF_SUCCESS;
2894 }
2895 else
2896 rc = VERR_VDI_NOT_OPENED;
2897 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
2898 return rc;
2899}
2900
2901static unsigned vmdkGetOpenFlags(void *pBackendData)
2902{
2903 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2904 unsigned uOpenFlags;
2905
2906 Assert(pImage);
2907
2908 if (pImage)
2909 uOpenFlags = pImage->uOpenFlags;
2910 else
2911 uOpenFlags = 0;
2912
2913 LogFlow(("%s: returned %d\n", __FUNCTION__, uOpenFlags));
2914 return uOpenFlags;
2915}
2916
2917static int vmdkSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
2918{
2919 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2920 int rc;
2921 const char *pszFilename;
2922
2923 /* Image must be opened and the new flags must be valid. Just readonly flag
2924 * is supported. */
2925 if (!pImage || uOpenFlags & ~VD_OPEN_FLAGS_READONLY)
2926 {
2927 rc = VERR_INVALID_PARAMETER;
2928 goto out;
2929 }
2930
2931 /* Implement this operation via reopening the image. */
2932 pszFilename = pImage->pszFilename;
2933 vmdkFreeImage(pImage, false);
2934 rc = vmdkOpenImage(pImage, pszFilename, uOpenFlags);
2935
2936out:
2937 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
2938 return rc;
2939}
2940
2941static int vmdkGetUuid(void *pBackendData, PRTUUID pUuid)
2942{
2943 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2944 int rc;
2945
2946 Assert(pImage);
2947
2948 if (pImage)
2949 {
2950 *pUuid = pImage->ImageUuid;
2951 rc = VINF_SUCCESS;
2952 }
2953 else
2954 rc = VERR_VDI_NOT_OPENED;
2955 LogFlow(("%s: returned %Vrc (%Vuuid)\n", __FUNCTION__, rc, pUuid));
2956 return rc;
2957}
2958
2959static int vmdkSetUuid(void *pBackendData, PCRTUUID pUuid)
2960{
2961 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2962 int rc;
2963
2964 LogFlow(("%s: %Vuuid\n", pUuid));
2965 Assert(pImage);
2966
2967 if (pImage)
2968 {
2969 pImage->ImageUuid = *pUuid;
2970 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2971 "ddb.uuid.image", pUuid);
2972 if (VBOX_FAILURE(rc))
2973 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
2974 rc = VINF_SUCCESS;
2975 }
2976 else
2977 rc = VERR_VDI_NOT_OPENED;
2978 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
2979 return rc;
2980}
2981
2982static int vmdkGetModificationUuid(void *pBackendData, PRTUUID pUuid)
2983{
2984 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
2985 int rc;
2986
2987 Assert(pImage);
2988
2989 if (pImage)
2990 {
2991 *pUuid = pImage->ModificationUuid;
2992 rc = VINF_SUCCESS;
2993 }
2994 else
2995 rc = VERR_VDI_NOT_OPENED;
2996 LogFlow(("%s: returned %Vrc (%Vuuid)\n", __FUNCTION__, rc, pUuid));
2997 return rc;
2998}
2999
3000static int vmdkSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
3001{
3002 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
3003 int rc;
3004
3005 LogFlow(("%s: %Vuuid\n", pUuid));
3006 Assert(pImage);
3007
3008 if (pImage)
3009 {
3010 pImage->ModificationUuid = *pUuid;
3011 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
3012 "ddb.uuid.modification", pUuid);
3013 if (VBOX_FAILURE(rc))
3014 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename);
3015 rc = VINF_SUCCESS;
3016 }
3017 else
3018 rc = VERR_VDI_NOT_OPENED;
3019 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
3020 return rc;
3021}
3022
3023static int vmdkGetParentUuid(void *pBackendData, PRTUUID pUuid)
3024{
3025 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
3026 int rc;
3027
3028 Assert(pImage);
3029
3030 if (pImage)
3031 {
3032 *pUuid = pImage->ParentUuid;
3033 rc = VINF_SUCCESS;
3034 }
3035 else
3036 rc = VERR_VDI_NOT_OPENED;
3037 LogFlow(("%s: returned %Vrc (%Vuuid)\n", __FUNCTION__, rc, pUuid));
3038 return rc;
3039}
3040
3041static int vmdkSetParentUuid(void *pBackendData, PCRTUUID pUuid)
3042{
3043 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
3044 int rc;
3045
3046 LogFlow(("%s: %Vuuid\n", pUuid));
3047 Assert(pImage);
3048
3049 if (pImage)
3050 {
3051 pImage->ParentUuid = *pUuid;
3052 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
3053 "ddb.uuid.parent", pUuid);
3054 if (VBOX_FAILURE(rc))
3055 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
3056 rc = VINF_SUCCESS;
3057 }
3058 else
3059 rc = VERR_VDI_NOT_OPENED;
3060 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
3061 return rc;
3062}
3063
3064
3065VBOXHDDBACKEND g_VmdkBackend =
3066{
3067 /* pfnOpen */
3068 vmdkOpen,
3069 /* pfnCreate */
3070 vmdkCreate,
3071 /* pfnClose */
3072 vmdkClose,
3073 /* pfnRead */
3074 vmdkRead,
3075 /* pfnWrite */
3076 vmdkWrite,
3077 /* pfnFlush */
3078 vmdkFlush,
3079 /* pfnGetImageType */
3080 vmdkGetImageType,
3081 /* pfnGetSize */
3082 vmdkGetSize,
3083 /* pfnGetGeometry */
3084 vmdkGetGeometry,
3085 /* pfnSetGeometry */
3086 vmdkSetGeometry,
3087 /* pfnGetTranslation */
3088 vmdkGetTranslation,
3089 /* pfnSetTranslation */
3090 vmdkSetTranslation,
3091 /* pfnGetOpenFlags */
3092 vmdkGetOpenFlags,
3093 /* pfnSetOpenFlags */
3094 vmdkSetOpenFlags,
3095 /* pfnGetUuid */
3096 vmdkGetUuid,
3097 /* pfnGetUuid */
3098 vmdkSetUuid,
3099 /* pfnGetModificationUuid */
3100 vmdkGetModificationUuid,
3101 /* pfnSetModificationUuid */
3102 vmdkSetModificationUuid,
3103 /* pfnGetParentUuid */
3104 vmdkGetParentUuid,
3105 /* pfnSetParentUuid */
3106 vmdkSetParentUuid
3107};
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