VirtualBox

source: vbox/trunk/src/VBox/Storage/VMDK.cpp@ 34885

Last change on this file since 34885 was 34885, checked in by vboxsync, 14 years ago

VMDK: Fix corruption

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 271.4 KB
Line 
1/* $Id: VMDK.cpp 34885 2010-12-09 13:56:03Z vboxsync $ */
2/** @file
3 * VMDK disk image, core code.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_VD_VMDK
22#include <VBox/vd-plugin.h>
23#include <VBox/err.h>
24
25#include <VBox/log.h>
26#include <iprt/assert.h>
27#include <iprt/alloc.h>
28#include <iprt/uuid.h>
29#include <iprt/path.h>
30#include <iprt/string.h>
31#include <iprt/rand.h>
32#include <iprt/zip.h>
33#include <iprt/asm.h>
34
35
36/*******************************************************************************
37* Constants And Macros, Structures and Typedefs *
38*******************************************************************************/
39
40/** Maximum encoded string size (including NUL) we allow for VMDK images.
41 * Deliberately not set high to avoid running out of descriptor space. */
42#define VMDK_ENCODED_COMMENT_MAX 1024
43
44/** VMDK descriptor DDB entry for PCHS cylinders. */
45#define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders"
46
47/** VMDK descriptor DDB entry for PCHS heads. */
48#define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads"
49
50/** VMDK descriptor DDB entry for PCHS sectors. */
51#define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors"
52
53/** VMDK descriptor DDB entry for LCHS cylinders. */
54#define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders"
55
56/** VMDK descriptor DDB entry for LCHS heads. */
57#define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads"
58
59/** VMDK descriptor DDB entry for LCHS sectors. */
60#define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors"
61
62/** VMDK descriptor DDB entry for image UUID. */
63#define VMDK_DDB_IMAGE_UUID "ddb.uuid.image"
64
65/** VMDK descriptor DDB entry for image modification UUID. */
66#define VMDK_DDB_MODIFICATION_UUID "ddb.uuid.modification"
67
68/** VMDK descriptor DDB entry for parent image UUID. */
69#define VMDK_DDB_PARENT_UUID "ddb.uuid.parent"
70
71/** VMDK descriptor DDB entry for parent image modification UUID. */
72#define VMDK_DDB_PARENT_MODIFICATION_UUID "ddb.uuid.parentmodification"
73
74/** No compression for streamOptimized files. */
75#define VMDK_COMPRESSION_NONE 0
76
77/** Deflate compression for streamOptimized files. */
78#define VMDK_COMPRESSION_DEFLATE 1
79
80/** Marker that the actual GD value is stored in the footer. */
81#define VMDK_GD_AT_END 0xffffffffffffffffULL
82
83/** Marker for end-of-stream in streamOptimized images. */
84#define VMDK_MARKER_EOS 0
85
86/** Marker for grain table block in streamOptimized images. */
87#define VMDK_MARKER_GT 1
88
89/** Marker for grain directory block in streamOptimized images. */
90#define VMDK_MARKER_GD 2
91
92/** Marker for footer in streamOptimized images. */
93#define VMDK_MARKER_FOOTER 3
94
95/** Dummy marker for "don't check the marker value". */
96#define VMDK_MARKER_IGNORE 0xffffffffU
97
98/**
99 * Magic number for hosted images created by VMware Workstation 4, VMware
100 * Workstation 5, VMware Server or VMware Player. Not necessarily sparse.
101 */
102#define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
103
104/**
105 * VMDK hosted binary extent header. The "Sparse" is a total misnomer, as
106 * this header is also used for monolithic flat images.
107 */
108#pragma pack(1)
109typedef struct SparseExtentHeader
110{
111 uint32_t magicNumber;
112 uint32_t version;
113 uint32_t flags;
114 uint64_t capacity;
115 uint64_t grainSize;
116 uint64_t descriptorOffset;
117 uint64_t descriptorSize;
118 uint32_t numGTEsPerGT;
119 uint64_t rgdOffset;
120 uint64_t gdOffset;
121 uint64_t overHead;
122 bool uncleanShutdown;
123 char singleEndLineChar;
124 char nonEndLineChar;
125 char doubleEndLineChar1;
126 char doubleEndLineChar2;
127 uint16_t compressAlgorithm;
128 uint8_t pad[433];
129} SparseExtentHeader;
130#pragma pack()
131
132/** VMDK capacity for a single chunk when 2G splitting is turned on. Should be
133 * divisible by the default grain size (64K) */
134#define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
135
136/** VMDK streamOptimized file format marker. The type field may or may not
137 * be actually valid, but there's always data to read there. */
138#pragma pack(1)
139typedef struct VMDKMARKER
140{
141 uint64_t uSector;
142 uint32_t cbSize;
143 uint32_t uType;
144} VMDKMARKER, *PVMDKMARKER;
145#pragma pack()
146
147
148#ifdef VBOX_WITH_VMDK_ESX
149
150/** @todo the ESX code is not tested, not used, and lacks error messages. */
151
152/**
153 * Magic number for images created by VMware GSX Server 3 or ESX Server 3.
154 */
155#define VMDK_ESX_SPARSE_MAGICNUMBER 0x44574f43 /* 'C' 'O' 'W' 'D' */
156
157#pragma pack(1)
158typedef struct COWDisk_Header
159{
160 uint32_t magicNumber;
161 uint32_t version;
162 uint32_t flags;
163 uint32_t numSectors;
164 uint32_t grainSize;
165 uint32_t gdOffset;
166 uint32_t numGDEntries;
167 uint32_t freeSector;
168 /* The spec incompletely documents quite a few further fields, but states
169 * that they are unused by the current format. Replace them by padding. */
170 char reserved1[1604];
171 uint32_t savedGeneration;
172 char reserved2[8];
173 uint32_t uncleanShutdown;
174 char padding[396];
175} COWDisk_Header;
176#pragma pack()
177#endif /* VBOX_WITH_VMDK_ESX */
178
179
180/** Convert sector number/size to byte offset/size. */
181#define VMDK_SECTOR2BYTE(u) ((uint64_t)(u) << 9)
182
183/** Convert byte offset/size to sector number/size. */
184#define VMDK_BYTE2SECTOR(u) ((u) >> 9)
185
186/**
187 * VMDK extent type.
188 */
189typedef enum VMDKETYPE
190{
191 /** Hosted sparse extent. */
192 VMDKETYPE_HOSTED_SPARSE = 1,
193 /** Flat extent. */
194 VMDKETYPE_FLAT,
195 /** Zero extent. */
196 VMDKETYPE_ZERO,
197 /** VMFS extent, used by ESX. */
198 VMDKETYPE_VMFS
199#ifdef VBOX_WITH_VMDK_ESX
200 ,
201 /** ESX sparse extent. */
202 VMDKETYPE_ESX_SPARSE
203#endif /* VBOX_WITH_VMDK_ESX */
204} VMDKETYPE, *PVMDKETYPE;
205
206/**
207 * VMDK access type for a extent.
208 */
209typedef enum VMDKACCESS
210{
211 /** No access allowed. */
212 VMDKACCESS_NOACCESS = 0,
213 /** Read-only access. */
214 VMDKACCESS_READONLY,
215 /** Read-write access. */
216 VMDKACCESS_READWRITE
217} VMDKACCESS, *PVMDKACCESS;
218
219/** Forward declaration for PVMDKIMAGE. */
220typedef struct VMDKIMAGE *PVMDKIMAGE;
221
222/**
223 * Extents files entry. Used for opening a particular file only once.
224 */
225typedef struct VMDKFILE
226{
227 /** Pointer to filename. Local copy. */
228 const char *pszFilename;
229 /** File open flags for consistency checking. */
230 unsigned fOpen;
231 /** Flag whether this file has been opened for async I/O. */
232 bool fAsyncIO;
233 /** Handle for sync/async file abstraction.*/
234 PVDIOSTORAGE pStorage;
235 /** Reference counter. */
236 unsigned uReferences;
237 /** Flag whether the file should be deleted on last close. */
238 bool fDelete;
239 /** Pointer to the image we belong to (for debugging purposes). */
240 PVMDKIMAGE pImage;
241 /** Pointer to next file descriptor. */
242 struct VMDKFILE *pNext;
243 /** Pointer to the previous file descriptor. */
244 struct VMDKFILE *pPrev;
245} VMDKFILE, *PVMDKFILE;
246
247/**
248 * VMDK extent data structure.
249 */
250typedef struct VMDKEXTENT
251{
252 /** File handle. */
253 PVMDKFILE pFile;
254 /** Base name of the image extent. */
255 const char *pszBasename;
256 /** Full name of the image extent. */
257 const char *pszFullname;
258 /** Number of sectors in this extent. */
259 uint64_t cSectors;
260 /** Number of sectors per block (grain in VMDK speak). */
261 uint64_t cSectorsPerGrain;
262 /** Starting sector number of descriptor. */
263 uint64_t uDescriptorSector;
264 /** Size of descriptor in sectors. */
265 uint64_t cDescriptorSectors;
266 /** Starting sector number of grain directory. */
267 uint64_t uSectorGD;
268 /** Starting sector number of redundant grain directory. */
269 uint64_t uSectorRGD;
270 /** Total number of metadata sectors. */
271 uint64_t cOverheadSectors;
272 /** Nominal size (i.e. as described by the descriptor) of this extent. */
273 uint64_t cNominalSectors;
274 /** Sector offset (i.e. as described by the descriptor) of this extent. */
275 uint64_t uSectorOffset;
276 /** Number of entries in a grain table. */
277 uint32_t cGTEntries;
278 /** Number of sectors reachable via a grain directory entry. */
279 uint32_t cSectorsPerGDE;
280 /** Number of entries in the grain directory. */
281 uint32_t cGDEntries;
282 /** Pointer to the next free sector. Legacy information. Do not use. */
283 uint32_t uFreeSector;
284 /** Number of this extent in the list of images. */
285 uint32_t uExtent;
286 /** Pointer to the descriptor (NULL if no descriptor in this extent). */
287 char *pDescData;
288 /** Pointer to the grain directory. */
289 uint32_t *pGD;
290 /** Pointer to the redundant grain directory. */
291 uint32_t *pRGD;
292 /** VMDK version of this extent. 1=1.0/1.1 */
293 uint32_t uVersion;
294 /** Type of this extent. */
295 VMDKETYPE enmType;
296 /** Access to this extent. */
297 VMDKACCESS enmAccess;
298 /** Flag whether this extent is marked as unclean. */
299 bool fUncleanShutdown;
300 /** Flag whether the metadata in the extent header needs to be updated. */
301 bool fMetaDirty;
302 /** Flag whether there is a footer in this extent. */
303 bool fFooter;
304 /** Compression type for this extent. */
305 uint16_t uCompression;
306 /** Append position for writing new grain. Only for sparse extents. */
307 uint64_t uAppendPosition;
308 /** Last grain which was accessed. Only for streamOptimized extents. */
309 uint32_t uLastGrainAccess;
310 /** Starting sector corresponding to the grain buffer. */
311 uint32_t uGrainSectorAbs;
312 /** Grain number corresponding to the grain buffer. */
313 uint32_t uGrain;
314 /** Actual size of the compressed data, only valid for reading. */
315 uint32_t cbGrainStreamRead;
316 /** Size of compressed grain buffer for streamOptimized extents. */
317 size_t cbCompGrain;
318 /** Compressed grain buffer for streamOptimized extents, with marker. */
319 void *pvCompGrain;
320 /** Decompressed grain buffer for streamOptimized extents. */
321 void *pvGrain;
322 /** Reference to the image in which this extent is used. Do not use this
323 * on a regular basis to avoid passing pImage references to functions
324 * explicitly. */
325 struct VMDKIMAGE *pImage;
326} VMDKEXTENT, *PVMDKEXTENT;
327
328/**
329 * Grain table cache size. Allocated per image.
330 */
331#define VMDK_GT_CACHE_SIZE 256
332
333/**
334 * Grain table block size. Smaller than an actual grain table block to allow
335 * more grain table blocks to be cached without having to allocate excessive
336 * amounts of memory for the cache.
337 */
338#define VMDK_GT_CACHELINE_SIZE 128
339
340
341/**
342 * Maximum number of lines in a descriptor file. Not worth the effort of
343 * making it variable. Descriptor files are generally very short (~20 lines),
344 * with the exception of sparse files split in 2G chunks, which need for the
345 * maximum size (almost 2T) exactly 1025 lines for the disk database.
346 */
347#define VMDK_DESCRIPTOR_LINES_MAX 1100U
348
349/**
350 * Parsed descriptor information. Allows easy access and update of the
351 * descriptor (whether separate file or not). Free form text files suck.
352 */
353typedef struct VMDKDESCRIPTOR
354{
355 /** Line number of first entry of the disk descriptor. */
356 unsigned uFirstDesc;
357 /** Line number of first entry in the extent description. */
358 unsigned uFirstExtent;
359 /** Line number of first disk database entry. */
360 unsigned uFirstDDB;
361 /** Total number of lines. */
362 unsigned cLines;
363 /** Total amount of memory available for the descriptor. */
364 size_t cbDescAlloc;
365 /** Set if descriptor has been changed and not yet written to disk. */
366 bool fDirty;
367 /** Array of pointers to the data in the descriptor. */
368 char *aLines[VMDK_DESCRIPTOR_LINES_MAX];
369 /** Array of line indices pointing to the next non-comment line. */
370 unsigned aNextLines[VMDK_DESCRIPTOR_LINES_MAX];
371} VMDKDESCRIPTOR, *PVMDKDESCRIPTOR;
372
373
374/**
375 * Cache entry for translating extent/sector to a sector number in that
376 * extent.
377 */
378typedef struct VMDKGTCACHEENTRY
379{
380 /** Extent number for which this entry is valid. */
381 uint32_t uExtent;
382 /** GT data block number. */
383 uint64_t uGTBlock;
384 /** Data part of the cache entry. */
385 uint32_t aGTData[VMDK_GT_CACHELINE_SIZE];
386} VMDKGTCACHEENTRY, *PVMDKGTCACHEENTRY;
387
388/**
389 * Cache data structure for blocks of grain table entries. For now this is a
390 * fixed size direct mapping cache, but this should be adapted to the size of
391 * the sparse image and maybe converted to a set-associative cache. The
392 * implementation below implements a write-through cache with write allocate.
393 */
394typedef struct VMDKGTCACHE
395{
396 /** Cache entries. */
397 VMDKGTCACHEENTRY aGTCache[VMDK_GT_CACHE_SIZE];
398 /** Number of cache entries (currently unused). */
399 unsigned cEntries;
400} VMDKGTCACHE, *PVMDKGTCACHE;
401
402/**
403 * Complete VMDK image data structure. Mainly a collection of extents and a few
404 * extra global data fields.
405 */
406typedef struct VMDKIMAGE
407{
408 /** Image name. */
409 const char *pszFilename;
410 /** Descriptor file if applicable. */
411 PVMDKFILE pFile;
412 /** I/O interface. */
413 PVDINTERFACE pInterfaceIO;
414 /** I/O interface callbacks. */
415 PVDINTERFACEIOINT pInterfaceIOCallbacks;
416
417 /** Pointer to the per-disk VD interface list. */
418 PVDINTERFACE pVDIfsDisk;
419 /** Pointer to the per-image VD interface list. */
420 PVDINTERFACE pVDIfsImage;
421
422 /** Error interface. */
423 PVDINTERFACE pInterfaceError;
424 /** Error interface callbacks. */
425 PVDINTERFACEERROR pInterfaceErrorCallbacks;
426
427 /** Pointer to the image extents. */
428 PVMDKEXTENT pExtents;
429 /** Number of image extents. */
430 unsigned cExtents;
431 /** Pointer to the files list, for opening a file referenced multiple
432 * times only once (happens mainly with raw partition access). */
433 PVMDKFILE pFiles;
434
435 /**
436 * Pointer to an array of segment entries for async I/O.
437 * This is an optimization because the task number to submit is not known
438 * and allocating/freeing an array in the read/write functions every time
439 * is too expensive.
440 */
441 PPDMDATASEG paSegments;
442 /** Entries available in the segments array. */
443 unsigned cSegments;
444
445 /** Open flags passed by VBoxHD layer. */
446 unsigned uOpenFlags;
447 /** Image flags defined during creation or determined during open. */
448 unsigned uImageFlags;
449 /** Total size of the image. */
450 uint64_t cbSize;
451 /** Physical geometry of this image. */
452 VDGEOMETRY PCHSGeometry;
453 /** Logical geometry of this image. */
454 VDGEOMETRY LCHSGeometry;
455 /** Image UUID. */
456 RTUUID ImageUuid;
457 /** Image modification UUID. */
458 RTUUID ModificationUuid;
459 /** Parent image UUID. */
460 RTUUID ParentUuid;
461 /** Parent image modification UUID. */
462 RTUUID ParentModificationUuid;
463
464 /** Pointer to grain table cache, if this image contains sparse extents. */
465 PVMDKGTCACHE pGTCache;
466 /** Pointer to the descriptor (NULL if no separate descriptor file). */
467 char *pDescData;
468 /** Allocation size of the descriptor file. */
469 size_t cbDescAlloc;
470 /** Parsed descriptor file content. */
471 VMDKDESCRIPTOR Descriptor;
472} VMDKIMAGE;
473
474
475/** State for the input/output callout of the inflate reader/deflate writer. */
476typedef struct VMDKCOMPRESSIO
477{
478 /* Image this operation relates to. */
479 PVMDKIMAGE pImage;
480 /* Current read position. */
481 ssize_t iOffset;
482 /* Size of the compressed grain buffer (available data). */
483 size_t cbCompGrain;
484 /* Pointer to the compressed grain buffer. */
485 void *pvCompGrain;
486} VMDKCOMPRESSIO;
487
488
489/** Tracks async grain allocation. */
490typedef struct VMDKGRAINALLOCASYNC
491{
492 /** Flag whether the allocation failed. */
493 bool fIoErr;
494 /** Current number of transfers pending.
495 * If reached 0 and there is an error the old state is restored. */
496 unsigned cIoXfersPending;
497 /** Sector number */
498 uint64_t uSector;
499 /** Flag whether the grain table needs to be updated. */
500 bool fGTUpdateNeeded;
501 /** Extent the allocation happens. */
502 PVMDKEXTENT pExtent;
503 /** Position of the new grain, required for the grain table update. */
504 uint64_t uGrainOffset;
505 /** Grain table sector. */
506 uint64_t uGTSector;
507 /** Backup grain table sector. */
508 uint64_t uRGTSector;
509} VMDKGRAINALLOCASYNC, *PVMDKGRAINALLOCASYNC;
510
511/*******************************************************************************
512* Static Variables *
513*******************************************************************************/
514
515/** NULL-terminated array of supported file extensions. */
516static const VDFILEEXTENSION s_aVmdkFileExtensions[] =
517{
518 {"vmdk", VDTYPE_HDD},
519 {NULL, VDTYPE_INVALID}
520};
521
522/*******************************************************************************
523* Internal Functions *
524*******************************************************************************/
525
526static void vmdkFreeStreamBuffers(PVMDKEXTENT pExtent);
527static void vmdkFreeExtentData(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
528 bool fDelete);
529
530static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
531static int vmdkFlushImage(PVMDKIMAGE pImage);
532static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment);
533static int vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
534
535static int vmdkAllocGrainAsyncComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq);
536
537/**
538 * Internal: signal an error to the frontend.
539 */
540DECLINLINE(int) vmdkError(PVMDKIMAGE pImage, int rc, RT_SRC_POS_DECL,
541 const char *pszFormat, ...)
542{
543 va_list va;
544 va_start(va, pszFormat);
545 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
546 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
547 pszFormat, va);
548 va_end(va);
549 return rc;
550}
551
552/**
553 * Internal: signal an informational message to the frontend.
554 */
555DECLINLINE(int) vmdkMessage(PVMDKIMAGE pImage, const char *pszFormat, ...)
556{
557 int rc = VINF_SUCCESS;
558 va_list va;
559 va_start(va, pszFormat);
560 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
561 rc = pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser,
562 pszFormat, va);
563 va_end(va);
564 return rc;
565}
566
567/**
568 * Internal: open a file (using a file descriptor cache to ensure each file
569 * is only opened once - anything else can cause locking problems).
570 */
571static int vmdkFileOpen(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile,
572 const char *pszFilename, uint32_t fOpen, bool fAsyncIO)
573{
574 int rc = VINF_SUCCESS;
575 PVMDKFILE pVmdkFile;
576
577 for (pVmdkFile = pImage->pFiles;
578 pVmdkFile != NULL;
579 pVmdkFile = pVmdkFile->pNext)
580 {
581 if (!strcmp(pszFilename, pVmdkFile->pszFilename))
582 {
583 Assert(fOpen == pVmdkFile->fOpen);
584 pVmdkFile->uReferences++;
585
586 *ppVmdkFile = pVmdkFile;
587
588 return rc;
589 }
590 }
591
592 /* If we get here, there's no matching entry in the cache. */
593 pVmdkFile = (PVMDKFILE)RTMemAllocZ(sizeof(VMDKFILE));
594 if (!VALID_PTR(pVmdkFile))
595 {
596 *ppVmdkFile = NULL;
597 return VERR_NO_MEMORY;
598 }
599
600 pVmdkFile->pszFilename = RTStrDup(pszFilename);
601 if (!VALID_PTR(pVmdkFile->pszFilename))
602 {
603 RTMemFree(pVmdkFile);
604 *ppVmdkFile = NULL;
605 return VERR_NO_MEMORY;
606 }
607 pVmdkFile->fOpen = fOpen;
608 pVmdkFile->fAsyncIO = fAsyncIO;
609
610 rc = pImage->pInterfaceIOCallbacks->pfnOpen(pImage->pInterfaceIO->pvUser,
611 pszFilename, fOpen,
612 &pVmdkFile->pStorage);
613 if (RT_SUCCESS(rc))
614 {
615 pVmdkFile->uReferences = 1;
616 pVmdkFile->pImage = pImage;
617 pVmdkFile->pNext = pImage->pFiles;
618 if (pImage->pFiles)
619 pImage->pFiles->pPrev = pVmdkFile;
620 pImage->pFiles = pVmdkFile;
621 *ppVmdkFile = pVmdkFile;
622 }
623 else
624 {
625 RTStrFree((char *)(void *)pVmdkFile->pszFilename);
626 RTMemFree(pVmdkFile);
627 *ppVmdkFile = NULL;
628 }
629
630 return rc;
631}
632
633/**
634 * Internal: close a file, updating the file descriptor cache.
635 */
636static int vmdkFileClose(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile, bool fDelete)
637{
638 int rc = VINF_SUCCESS;
639 PVMDKFILE pVmdkFile = *ppVmdkFile;
640
641 AssertPtr(pVmdkFile);
642
643 pVmdkFile->fDelete |= fDelete;
644 Assert(pVmdkFile->uReferences);
645 pVmdkFile->uReferences--;
646 if (pVmdkFile->uReferences == 0)
647 {
648 PVMDKFILE pPrev;
649 PVMDKFILE pNext;
650
651 /* Unchain the element from the list. */
652 pPrev = pVmdkFile->pPrev;
653 pNext = pVmdkFile->pNext;
654
655 if (pNext)
656 pNext->pPrev = pPrev;
657 if (pPrev)
658 pPrev->pNext = pNext;
659 else
660 pImage->pFiles = pNext;
661
662 rc = pImage->pInterfaceIOCallbacks->pfnClose(pImage->pInterfaceIO->pvUser,
663 pVmdkFile->pStorage);
664 if (RT_SUCCESS(rc) && pVmdkFile->fDelete)
665 rc = pImage->pInterfaceIOCallbacks->pfnDelete(pImage->pInterfaceIO->pvUser,
666 pVmdkFile->pszFilename);
667 RTStrFree((char *)(void *)pVmdkFile->pszFilename);
668 RTMemFree(pVmdkFile);
669 }
670
671 *ppVmdkFile = NULL;
672 return rc;
673}
674
675/**
676 * Internal: rename a file (sync)
677 */
678DECLINLINE(int) vmdkFileMove(PVMDKIMAGE pImage, const char *pszSrc,
679 const char *pszDst, unsigned fMove)
680{
681 return pImage->pInterfaceIOCallbacks->pfnMove(pImage->pInterfaceIO->pvUser,
682 pszSrc, pszDst, fMove);
683}
684
685/**
686 * Internal: get the size of a file (sync/async)
687 */
688DECLINLINE(int) vmdkFileGetSize(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
689 uint64_t *pcbSize)
690{
691 return pImage->pInterfaceIOCallbacks->pfnGetSize(pImage->pInterfaceIO->pvUser,
692 pVmdkFile->pStorage,
693 pcbSize);
694}
695
696/**
697 * Internal: set the size of a file (sync/async)
698 */
699DECLINLINE(int) vmdkFileSetSize(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
700 uint64_t cbSize)
701{
702 return pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
703 pVmdkFile->pStorage,
704 cbSize);
705}
706
707/**
708 * Internal: read from a file (sync)
709 */
710DECLINLINE(int) vmdkFileReadSync(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
711 uint64_t uOffset, void *pvBuf,
712 size_t cbToRead, size_t *pcbRead)
713{
714 return pImage->pInterfaceIOCallbacks->pfnReadSync(pImage->pInterfaceIO->pvUser,
715 pVmdkFile->pStorage, uOffset,
716 pvBuf, cbToRead, pcbRead);
717}
718
719/**
720 * Internal: write to a file (sync)
721 */
722DECLINLINE(int) vmdkFileWriteSync(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
723 uint64_t uOffset, const void *pvBuf,
724 size_t cbToWrite, size_t *pcbWritten)
725{
726 return pImage->pInterfaceIOCallbacks->pfnWriteSync(pImage->pInterfaceIO->pvUser,
727 pVmdkFile->pStorage, uOffset,
728 pvBuf, cbToWrite, pcbWritten);
729}
730
731/**
732 * Internal: flush a file (sync)
733 */
734DECLINLINE(int) vmdkFileFlush(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile)
735{
736 return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
737 pVmdkFile->pStorage);
738}
739
740/**
741 * Internal: read user data (async)
742 */
743DECLINLINE(int) vmdkFileReadUserAsync(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
744 uint64_t uOffset, PVDIOCTX pIoCtx,
745 size_t cbRead)
746{
747 return pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
748 pVmdkFile->pStorage,
749 uOffset, pIoCtx,
750 cbRead);
751}
752
753/**
754 * Internal: write user data (async)
755 */
756DECLINLINE(int) vmdkFileWriteUserAsync(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
757 uint64_t uOffset, PVDIOCTX pIoCtx,
758 size_t cbWrite,
759 PFNVDXFERCOMPLETED pfnComplete,
760 void *pvCompleteUser)
761{
762 return pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
763 pVmdkFile->pStorage,
764 uOffset, pIoCtx,
765 cbWrite,
766 pfnComplete,
767 pvCompleteUser);
768}
769
770/**
771 * Internal: read metadata (async)
772 */
773DECLINLINE(int) vmdkFileReadMetaAsync(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
774 uint64_t uOffset, void *pvBuffer,
775 size_t cbBuffer, PVDIOCTX pIoCtx,
776 PPVDMETAXFER ppMetaXfer,
777 PFNVDXFERCOMPLETED pfnComplete,
778 void *pvCompleteUser)
779{
780 return pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser,
781 pVmdkFile->pStorage,
782 uOffset, pvBuffer,
783 cbBuffer, pIoCtx,
784 ppMetaXfer,
785 pfnComplete,
786 pvCompleteUser);
787}
788
789/**
790 * Internal: write metadata (async)
791 */
792DECLINLINE(int) vmdkFileWriteMetaAsync(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
793 uint64_t uOffset, void *pvBuffer,
794 size_t cbBuffer, PVDIOCTX pIoCtx,
795 PFNVDXFERCOMPLETED pfnComplete,
796 void *pvCompleteUser)
797{
798 return pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
799 pVmdkFile->pStorage,
800 uOffset, pvBuffer,
801 cbBuffer, pIoCtx,
802 pfnComplete,
803 pvCompleteUser);
804}
805
806/**
807 * Internal: releases a metadata transfer handle (async)
808 */
809DECLINLINE(void) vmdkFileMetaXferRelease(PVMDKIMAGE pImage, PVDMETAXFER pMetaXfer)
810{
811 pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser,
812 pMetaXfer);
813}
814
815/**
816 * Internal: flush a file (async)
817 */
818DECLINLINE(int) vmdkFileFlushAsync(PVMDKIMAGE pImage, PVMDKFILE pVmdkFile,
819 PVDIOCTX pIoCtx)
820{
821 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
822 pVmdkFile->pStorage, pIoCtx,
823 NULL, NULL);
824}
825
826/**
827 * Internal: sets the buffer to a specific byte (async)
828 */
829DECLINLINE(int) vmdkFileIoCtxSet(PVMDKIMAGE pImage, PVDIOCTX pIoCtx,
830 int ch, size_t cbSet)
831{
832 return pImage->pInterfaceIOCallbacks->pfnIoCtxSet(pImage->pInterfaceIO->pvUser,
833 pIoCtx, ch, cbSet);
834}
835
836
837static DECLCALLBACK(int) vmdkFileInflateHelper(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
838{
839 VMDKCOMPRESSIO *pInflateState = (VMDKCOMPRESSIO *)pvUser;
840 size_t cbInjected = 0;
841
842 Assert(cbBuf);
843 if (pInflateState->iOffset < 0)
844 {
845 *(uint8_t *)pvBuf = RTZIPTYPE_ZLIB;
846 pvBuf = (uint8_t *)pvBuf + 1;
847 cbBuf--;
848 cbInjected = 1;
849 pInflateState->iOffset = RT_OFFSETOF(VMDKMARKER, uType);
850 }
851 if (!cbBuf)
852 {
853 if (pcbBuf)
854 *pcbBuf = cbInjected;
855 return VINF_SUCCESS;
856 }
857 cbBuf = RT_MIN(cbBuf, pInflateState->cbCompGrain - pInflateState->iOffset);
858 memcpy(pvBuf,
859 (uint8_t *)pInflateState->pvCompGrain + pInflateState->iOffset,
860 cbBuf);
861 pInflateState->iOffset += cbBuf;
862 Assert(pcbBuf);
863 *pcbBuf = cbBuf + cbInjected;
864 return VINF_SUCCESS;
865}
866
867/**
868 * Internal: read from a file and inflate the compressed data,
869 * distinguishing between async and normal operation
870 */
871DECLINLINE(int) vmdkFileInflateSync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
872 uint64_t uOffset, void *pvBuf,
873 size_t cbToRead, const void *pcvMarker,
874 uint64_t *puLBA, uint32_t *pcbMarkerData)
875{
876 if (pExtent->pFile->fAsyncIO)
877 {
878 AssertMsgFailed(("TODO\n"));
879 return VERR_NOT_SUPPORTED;
880 }
881 else
882 {
883 int rc;
884 PRTZIPDECOMP pZip = NULL;
885 VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
886 size_t cbCompSize, cbActuallyRead;
887
888 if (!pcvMarker)
889 {
890 rc = vmdkFileReadSync(pImage, pExtent->pFile, uOffset, pMarker,
891 RT_OFFSETOF(VMDKMARKER, uType), NULL);
892 if (RT_FAILURE(rc))
893 return rc;
894 }
895 else
896 memcpy(pMarker, pcvMarker, RT_OFFSETOF(VMDKMARKER, uType));
897
898 cbCompSize = RT_LE2H_U32(pMarker->cbSize);
899 if (cbCompSize == 0)
900 {
901 AssertMsgFailed(("VMDK: corrupted marker\n"));
902 return VERR_VD_VMDK_INVALID_FORMAT;
903 }
904
905 /* Sanity check - the expansion ratio should be much less than 2. */
906 Assert(cbCompSize < 2 * cbToRead);
907 if (cbCompSize >= 2 * cbToRead)
908 return VERR_VD_VMDK_INVALID_FORMAT;
909
910 /* Compressed grain marker. Data follows immediately. */
911 rc = vmdkFileReadSync(pImage, pExtent->pFile,
912 uOffset + RT_OFFSETOF(VMDKMARKER, uType),
913 (uint8_t *)pExtent->pvCompGrain
914 + RT_OFFSETOF(VMDKMARKER, uType),
915 RT_ALIGN_Z( cbCompSize
916 + RT_OFFSETOF(VMDKMARKER, uType),
917 512)
918 - RT_OFFSETOF(VMDKMARKER, uType), NULL);
919
920 if (puLBA)
921 *puLBA = RT_LE2H_U64(pMarker->uSector);
922 if (pcbMarkerData)
923 *pcbMarkerData = RT_ALIGN( cbCompSize
924 + RT_OFFSETOF(VMDKMARKER, uType),
925 512);
926
927 VMDKCOMPRESSIO InflateState;
928 InflateState.pImage = pImage;
929 InflateState.iOffset = -1;
930 InflateState.cbCompGrain = cbCompSize + RT_OFFSETOF(VMDKMARKER, uType);
931 InflateState.pvCompGrain = pExtent->pvCompGrain;
932
933 rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper);
934 if (RT_FAILURE(rc))
935 return rc;
936 rc = RTZipDecompress(pZip, pvBuf, cbToRead, &cbActuallyRead);
937 RTZipDecompDestroy(pZip);
938 if (RT_FAILURE(rc))
939 return rc;
940 if (cbActuallyRead != cbToRead)
941 rc = VERR_VD_VMDK_INVALID_FORMAT;
942 return rc;
943 }
944}
945
946static DECLCALLBACK(int) vmdkFileDeflateHelper(void *pvUser, const void *pvBuf, size_t cbBuf)
947{
948 VMDKCOMPRESSIO *pDeflateState = (VMDKCOMPRESSIO *)pvUser;
949
950 Assert(cbBuf);
951 if (pDeflateState->iOffset < 0)
952 {
953 pvBuf = (const uint8_t *)pvBuf + 1;
954 cbBuf--;
955 pDeflateState->iOffset = RT_OFFSETOF(VMDKMARKER, uType);
956 }
957 if (!cbBuf)
958 return VINF_SUCCESS;
959 if (pDeflateState->iOffset + cbBuf > pDeflateState->cbCompGrain)
960 return VERR_BUFFER_OVERFLOW;
961 memcpy((uint8_t *)pDeflateState->pvCompGrain + pDeflateState->iOffset,
962 pvBuf, cbBuf);
963 pDeflateState->iOffset += cbBuf;
964 return VINF_SUCCESS;
965}
966
967/**
968 * Internal: deflate the uncompressed data and write to a file,
969 * distinguishing between async and normal operation
970 */
971DECLINLINE(int) vmdkFileDeflateSync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
972 uint64_t uOffset, const void *pvBuf,
973 size_t cbToWrite, uint64_t uLBA,
974 uint32_t *pcbMarkerData)
975{
976 if (pExtent->pFile->fAsyncIO)
977 {
978 AssertMsgFailed(("TODO\n"));
979 return VERR_NOT_SUPPORTED;
980 }
981 else
982 {
983 int rc;
984 PRTZIPCOMP pZip = NULL;
985 VMDKCOMPRESSIO DeflateState;
986
987 DeflateState.pImage = pImage;
988 DeflateState.iOffset = -1;
989 DeflateState.cbCompGrain = pExtent->cbCompGrain;
990 DeflateState.pvCompGrain = pExtent->pvCompGrain;
991
992 rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper,
993 RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT);
994 if (RT_FAILURE(rc))
995 return rc;
996 rc = RTZipCompress(pZip, pvBuf, cbToWrite);
997 if (RT_SUCCESS(rc))
998 rc = RTZipCompFinish(pZip);
999 RTZipCompDestroy(pZip);
1000 if (RT_SUCCESS(rc))
1001 {
1002 Assert( DeflateState.iOffset > 0
1003 && (size_t)DeflateState.iOffset <= DeflateState.cbCompGrain);
1004
1005 /* pad with zeroes to get to a full sector size */
1006 uint32_t uSize = DeflateState.iOffset;
1007 if (uSize % 512)
1008 {
1009 uint32_t uSizeAlign = RT_ALIGN(uSize, 512);
1010 memset((uint8_t *)pExtent->pvCompGrain + uSize, '\0',
1011 uSizeAlign - uSize);
1012 uSize = uSizeAlign;
1013 }
1014
1015 if (pcbMarkerData)
1016 *pcbMarkerData = uSize;
1017
1018 /* Compressed grain marker. Data follows immediately. */
1019 VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
1020 pMarker->uSector = RT_H2LE_U64(uLBA);
1021 pMarker->cbSize = RT_H2LE_U32( DeflateState.iOffset
1022 - RT_OFFSETOF(VMDKMARKER, uType));
1023 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uOffset, pMarker,
1024 uSize, NULL);
1025 if (RT_FAILURE(rc))
1026 return rc;
1027 }
1028 return rc;
1029 }
1030}
1031
1032
1033/**
1034 * Internal: check if all files are closed, prevent leaking resources.
1035 */
1036static int vmdkFileCheckAllClose(PVMDKIMAGE pImage)
1037{
1038 int rc = VINF_SUCCESS, rc2;
1039 PVMDKFILE pVmdkFile;
1040
1041 Assert(pImage->pFiles == NULL);
1042 for (pVmdkFile = pImage->pFiles;
1043 pVmdkFile != NULL;
1044 pVmdkFile = pVmdkFile->pNext)
1045 {
1046 LogRel(("VMDK: leaking reference to file \"%s\"\n",
1047 pVmdkFile->pszFilename));
1048 pImage->pFiles = pVmdkFile->pNext;
1049
1050 rc2 = vmdkFileClose(pImage, &pVmdkFile, pVmdkFile->fDelete);
1051
1052 if (RT_SUCCESS(rc))
1053 rc = rc2;
1054 }
1055 return rc;
1056}
1057
1058/**
1059 * Internal: truncate a string (at a UTF8 code point boundary) and encode the
1060 * critical non-ASCII characters.
1061 */
1062static char *vmdkEncodeString(const char *psz)
1063{
1064 char szEnc[VMDK_ENCODED_COMMENT_MAX + 3];
1065 char *pszDst = szEnc;
1066
1067 AssertPtr(psz);
1068
1069 for (; *psz; psz = RTStrNextCp(psz))
1070 {
1071 char *pszDstPrev = pszDst;
1072 RTUNICP Cp = RTStrGetCp(psz);
1073 if (Cp == '\\')
1074 {
1075 pszDst = RTStrPutCp(pszDst, Cp);
1076 pszDst = RTStrPutCp(pszDst, Cp);
1077 }
1078 else if (Cp == '\n')
1079 {
1080 pszDst = RTStrPutCp(pszDst, '\\');
1081 pszDst = RTStrPutCp(pszDst, 'n');
1082 }
1083 else if (Cp == '\r')
1084 {
1085 pszDst = RTStrPutCp(pszDst, '\\');
1086 pszDst = RTStrPutCp(pszDst, 'r');
1087 }
1088 else
1089 pszDst = RTStrPutCp(pszDst, Cp);
1090 if (pszDst - szEnc >= VMDK_ENCODED_COMMENT_MAX - 1)
1091 {
1092 pszDst = pszDstPrev;
1093 break;
1094 }
1095 }
1096 *pszDst = '\0';
1097 return RTStrDup(szEnc);
1098}
1099
1100/**
1101 * Internal: decode a string and store it into the specified string.
1102 */
1103static int vmdkDecodeString(const char *pszEncoded, char *psz, size_t cb)
1104{
1105 int rc = VINF_SUCCESS;
1106 char szBuf[4];
1107
1108 if (!cb)
1109 return VERR_BUFFER_OVERFLOW;
1110
1111 AssertPtr(psz);
1112
1113 for (; *pszEncoded; pszEncoded = RTStrNextCp(pszEncoded))
1114 {
1115 char *pszDst = szBuf;
1116 RTUNICP Cp = RTStrGetCp(pszEncoded);
1117 if (Cp == '\\')
1118 {
1119 pszEncoded = RTStrNextCp(pszEncoded);
1120 RTUNICP CpQ = RTStrGetCp(pszEncoded);
1121 if (CpQ == 'n')
1122 RTStrPutCp(pszDst, '\n');
1123 else if (CpQ == 'r')
1124 RTStrPutCp(pszDst, '\r');
1125 else if (CpQ == '\0')
1126 {
1127 rc = VERR_VD_VMDK_INVALID_HEADER;
1128 break;
1129 }
1130 else
1131 RTStrPutCp(pszDst, CpQ);
1132 }
1133 else
1134 pszDst = RTStrPutCp(pszDst, Cp);
1135
1136 /* Need to leave space for terminating NUL. */
1137 if ((size_t)(pszDst - szBuf) + 1 >= cb)
1138 {
1139 rc = VERR_BUFFER_OVERFLOW;
1140 break;
1141 }
1142 memcpy(psz, szBuf, pszDst - szBuf);
1143 psz += pszDst - szBuf;
1144 }
1145 *psz = '\0';
1146 return rc;
1147}
1148
1149/**
1150 * Internal: free all buffers associated with grain directories.
1151 */
1152static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent)
1153{
1154 if (pExtent->pGD)
1155 {
1156 RTMemFree(pExtent->pGD);
1157 pExtent->pGD = NULL;
1158 }
1159 if (pExtent->pRGD)
1160 {
1161 RTMemFree(pExtent->pRGD);
1162 pExtent->pRGD = NULL;
1163 }
1164}
1165
1166/**
1167 * Internal: allocate the compressed/uncompressed buffers for streamOptimized
1168 * images.
1169 */
1170static int vmdkAllocStreamBuffers(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
1171{
1172 int rc = VINF_SUCCESS;
1173
1174 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
1175 {
1176 /* streamOptimized extents need a compressed grain buffer, which must
1177 * be big enough to hold uncompressible data (which needs ~8 bytes
1178 * more than the uncompressed data), the marker and padding. */
1179 pExtent->cbCompGrain = RT_ALIGN_Z( VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
1180 + 8 + sizeof(VMDKMARKER), 512);
1181 pExtent->pvCompGrain = RTMemAlloc(pExtent->cbCompGrain);
1182 if (!pExtent->pvCompGrain)
1183 {
1184 rc = VERR_NO_MEMORY;
1185 goto out;
1186 }
1187
1188 /* streamOptimized extents need a decompressed grain buffer. */
1189 pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
1190 if (!pExtent->pvGrain)
1191 {
1192 rc = VERR_NO_MEMORY;
1193 goto out;
1194 }
1195 }
1196
1197out:
1198 if (RT_FAILURE(rc))
1199 vmdkFreeStreamBuffers(pExtent);
1200 return rc;
1201}
1202
1203/**
1204 * Internal: allocate all buffers associated with grain directories.
1205 */
1206static int vmdkAllocGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
1207{
1208 int rc = VINF_SUCCESS;
1209 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
1210 uint32_t *pGD = NULL, *pRGD = NULL;
1211
1212 pGD = (uint32_t *)RTMemAllocZ(cbGD);
1213 if (!pGD)
1214 {
1215 rc = VERR_NO_MEMORY;
1216 goto out;
1217 }
1218 pExtent->pGD = pGD;
1219
1220 if (pExtent->uSectorRGD)
1221 {
1222 pRGD = (uint32_t *)RTMemAllocZ(cbGD);
1223 if (!pRGD)
1224 {
1225 rc = VERR_NO_MEMORY;
1226 goto out;
1227 }
1228 pExtent->pRGD = pRGD;
1229 }
1230
1231out:
1232 if (RT_FAILURE(rc))
1233 vmdkFreeGrainDirectory(pExtent);
1234 return rc;
1235}
1236
1237static int vmdkReadGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
1238{
1239 int rc = VINF_SUCCESS;
1240 unsigned i;
1241 uint32_t *pGDTmp, *pRGDTmp;
1242 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
1243
1244 if (pExtent->enmType != VMDKETYPE_HOSTED_SPARSE)
1245 goto out;
1246
1247 if ( pExtent->uSectorGD == VMDK_GD_AT_END
1248 || pExtent->uSectorRGD == VMDK_GD_AT_END)
1249 {
1250 rc = VERR_INTERNAL_ERROR;
1251 goto out;
1252 }
1253
1254 rc = vmdkAllocGrainDirectory(pImage, pExtent);
1255 if (RT_FAILURE(rc))
1256 goto out;
1257
1258 /* The VMDK 1.1 spec seems to talk about compressed grain directories,
1259 * but in reality they are not compressed. */
1260 rc = vmdkFileReadSync(pImage, pExtent->pFile,
1261 VMDK_SECTOR2BYTE(pExtent->uSectorGD),
1262 pExtent->pGD, cbGD, NULL);
1263 AssertRC(rc);
1264 if (RT_FAILURE(rc))
1265 {
1266 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname);
1267 goto out;
1268 }
1269 for (i = 0, pGDTmp = pExtent->pGD; i < pExtent->cGDEntries; i++, pGDTmp++)
1270 *pGDTmp = RT_LE2H_U32(*pGDTmp);
1271
1272 if (pExtent->uSectorRGD)
1273 {
1274 /* The VMDK 1.1 spec seems to talk about compressed grain directories,
1275 * but in reality they are not compressed. */
1276 rc = vmdkFileReadSync(pImage, pExtent->pFile,
1277 VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
1278 pExtent->pRGD, cbGD, NULL);
1279 AssertRC(rc);
1280 if (RT_FAILURE(rc))
1281 {
1282 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not read redundant grain directory in '%s'"), pExtent->pszFullname);
1283 goto out;
1284 }
1285 for (i = 0, pRGDTmp = pExtent->pRGD; i < pExtent->cGDEntries; i++, pRGDTmp++)
1286 *pRGDTmp = RT_LE2H_U32(*pRGDTmp);
1287
1288 /* Check grain table and redundant grain table for consistency. */
1289 size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t);
1290 uint32_t *pTmpGT1 = (uint32_t *)RTMemTmpAlloc(cbGT);
1291 if (!pTmpGT1)
1292 {
1293 rc = VERR_NO_MEMORY;
1294 goto out;
1295 }
1296 uint32_t *pTmpGT2 = (uint32_t *)RTMemTmpAlloc(cbGT);
1297 if (!pTmpGT2)
1298 {
1299 RTMemTmpFree(pTmpGT1);
1300 rc = VERR_NO_MEMORY;
1301 goto out;
1302 }
1303
1304 for (i = 0, pGDTmp = pExtent->pGD, pRGDTmp = pExtent->pRGD;
1305 i < pExtent->cGDEntries;
1306 i++, pGDTmp++, pRGDTmp++)
1307 {
1308 /* If no grain table is allocated skip the entry. */
1309 if (*pGDTmp == 0 && *pRGDTmp == 0)
1310 continue;
1311
1312 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
1313 {
1314 /* Just one grain directory entry refers to a not yet allocated
1315 * grain table or both grain directory copies refer to the same
1316 * grain table. Not allowed. */
1317 RTMemTmpFree(pTmpGT1);
1318 RTMemTmpFree(pTmpGT2);
1319 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname);
1320 goto out;
1321 }
1322 /* The VMDK 1.1 spec seems to talk about compressed grain tables,
1323 * but in reality they are not compressed. */
1324 rc = vmdkFileReadSync(pImage, pExtent->pFile,
1325 VMDK_SECTOR2BYTE(*pGDTmp),
1326 pTmpGT1, cbGT, NULL);
1327 if (RT_FAILURE(rc))
1328 {
1329 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname);
1330 RTMemTmpFree(pTmpGT1);
1331 RTMemTmpFree(pTmpGT2);
1332 goto out;
1333 }
1334 /* The VMDK 1.1 spec seems to talk about compressed grain tables,
1335 * but in reality they are not compressed. */
1336 rc = vmdkFileReadSync(pImage, pExtent->pFile,
1337 VMDK_SECTOR2BYTE(*pRGDTmp),
1338 pTmpGT2, cbGT, NULL);
1339 if (RT_FAILURE(rc))
1340 {
1341 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading backup grain table in '%s'"), pExtent->pszFullname);
1342 RTMemTmpFree(pTmpGT1);
1343 RTMemTmpFree(pTmpGT2);
1344 goto out;
1345 }
1346 if (memcmp(pTmpGT1, pTmpGT2, cbGT))
1347 {
1348 RTMemTmpFree(pTmpGT1);
1349 RTMemTmpFree(pTmpGT2);
1350 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname);
1351 goto out;
1352 }
1353 }
1354
1355 /** @todo figure out what to do for unclean VMDKs. */
1356 RTMemTmpFree(pTmpGT1);
1357 RTMemTmpFree(pTmpGT2);
1358 }
1359
1360out:
1361 if (RT_FAILURE(rc))
1362 vmdkFreeGrainDirectory(pExtent);
1363 return rc;
1364}
1365
1366static int vmdkCreateGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
1367 uint64_t uStartSector, bool fPreAlloc)
1368{
1369 int rc = VINF_SUCCESS;
1370 unsigned i;
1371 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
1372 size_t cbGDRounded = RT_ALIGN_64(pExtent->cGDEntries * sizeof(uint32_t), 512);
1373 size_t cbGTRounded;
1374 uint64_t cbOverhead;
1375
1376 if (fPreAlloc)
1377 {
1378 cbGTRounded = RT_ALIGN_64(pExtent->cGDEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
1379 cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded
1380 + cbGTRounded;
1381 }
1382 else
1383 {
1384 /* Use a dummy start sector for layout computation. */
1385 if (uStartSector == VMDK_GD_AT_END)
1386 uStartSector = 1;
1387 cbGTRounded = 0;
1388 cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded;
1389 }
1390
1391 /* For streamOptimized extents there is only one grain directory,
1392 * and for all others take redundant grain directory into account. */
1393 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
1394 {
1395 cbOverhead = RT_ALIGN_64(cbOverhead,
1396 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
1397 }
1398 else
1399 {
1400 cbOverhead += cbGDRounded + cbGTRounded;
1401 cbOverhead = RT_ALIGN_64(cbOverhead,
1402 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
1403 rc = vmdkFileSetSize(pImage, pExtent->pFile, cbOverhead);
1404 }
1405 if (RT_FAILURE(rc))
1406 goto out;
1407 pExtent->uAppendPosition = cbOverhead;
1408 pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
1409
1410 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
1411 {
1412 pExtent->uSectorRGD = 0;
1413 pExtent->uSectorGD = uStartSector;
1414 }
1415 else
1416 {
1417 pExtent->uSectorRGD = uStartSector;
1418 pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
1419 }
1420
1421 rc = vmdkAllocStreamBuffers(pImage, pExtent);
1422 if (RT_FAILURE(rc))
1423 goto out;
1424
1425 rc = vmdkAllocGrainDirectory(pImage, pExtent);
1426 if (RT_FAILURE(rc))
1427 goto out;
1428
1429 if (fPreAlloc)
1430 {
1431 uint32_t uGTSectorLE;
1432 uint64_t uOffsetSectors;
1433
1434 if (pExtent->pRGD)
1435 {
1436 uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded);
1437 for (i = 0; i < pExtent->cGDEntries; i++)
1438 {
1439 pExtent->pRGD[i] = uOffsetSectors;
1440 uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
1441 /* Write the redundant grain directory entry to disk. */
1442 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
1443 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
1444 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
1445 if (RT_FAILURE(rc))
1446 {
1447 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
1448 goto out;
1449 }
1450 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
1451 }
1452 }
1453
1454 uOffsetSectors = pExtent->uSectorGD + VMDK_BYTE2SECTOR(cbGDRounded);
1455 for (i = 0; i < pExtent->cGDEntries; i++)
1456 {
1457 pExtent->pGD[i] = uOffsetSectors;
1458 uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
1459 /* Write the grain directory entry to disk. */
1460 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
1461 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
1462 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
1463 if (RT_FAILURE(rc))
1464 {
1465 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
1466 goto out;
1467 }
1468 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
1469 }
1470 }
1471
1472out:
1473 if (RT_FAILURE(rc))
1474 vmdkFreeGrainDirectory(pExtent);
1475 return rc;
1476}
1477
1478static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr,
1479 char **ppszUnquoted, char **ppszNext)
1480{
1481 char *pszQ;
1482 char *pszUnquoted;
1483
1484 /* Skip over whitespace. */
1485 while (*pszStr == ' ' || *pszStr == '\t')
1486 pszStr++;
1487
1488 if (*pszStr != '"')
1489 {
1490 pszQ = (char *)pszStr;
1491 while (*pszQ && *pszQ != ' ' && *pszQ != '\t')
1492 pszQ++;
1493 }
1494 else
1495 {
1496 pszStr++;
1497 pszQ = (char *)strchr(pszStr, '"');
1498 if (pszQ == NULL)
1499 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s'"), pImage->pszFilename);
1500 }
1501
1502 pszUnquoted = (char *)RTMemTmpAlloc(pszQ - pszStr + 1);
1503 if (!pszUnquoted)
1504 return VERR_NO_MEMORY;
1505 memcpy(pszUnquoted, pszStr, pszQ - pszStr);
1506 pszUnquoted[pszQ - pszStr] = '\0';
1507 *ppszUnquoted = pszUnquoted;
1508 if (ppszNext)
1509 *ppszNext = pszQ + 1;
1510 return VINF_SUCCESS;
1511}
1512
1513static int vmdkDescInitStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1514 const char *pszLine)
1515{
1516 char *pEnd = pDescriptor->aLines[pDescriptor->cLines];
1517 ssize_t cbDiff = strlen(pszLine) + 1;
1518
1519 if ( pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1
1520 && pEnd - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
1521 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
1522
1523 memcpy(pEnd, pszLine, cbDiff);
1524 pDescriptor->cLines++;
1525 pDescriptor->aLines[pDescriptor->cLines] = pEnd + cbDiff;
1526 pDescriptor->fDirty = true;
1527
1528 return VINF_SUCCESS;
1529}
1530
1531static bool vmdkDescGetStr(PVMDKDESCRIPTOR pDescriptor, unsigned uStart,
1532 const char *pszKey, const char **ppszValue)
1533{
1534 size_t cbKey = strlen(pszKey);
1535 const char *pszValue;
1536
1537 while (uStart != 0)
1538 {
1539 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
1540 {
1541 /* Key matches, check for a '=' (preceded by whitespace). */
1542 pszValue = pDescriptor->aLines[uStart] + cbKey;
1543 while (*pszValue == ' ' || *pszValue == '\t')
1544 pszValue++;
1545 if (*pszValue == '=')
1546 {
1547 *ppszValue = pszValue + 1;
1548 break;
1549 }
1550 }
1551 uStart = pDescriptor->aNextLines[uStart];
1552 }
1553 return !!uStart;
1554}
1555
1556static int vmdkDescSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1557 unsigned uStart,
1558 const char *pszKey, const char *pszValue)
1559{
1560 char *pszTmp;
1561 size_t cbKey = strlen(pszKey);
1562 unsigned uLast = 0;
1563
1564 while (uStart != 0)
1565 {
1566 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
1567 {
1568 /* Key matches, check for a '=' (preceded by whitespace). */
1569 pszTmp = pDescriptor->aLines[uStart] + cbKey;
1570 while (*pszTmp == ' ' || *pszTmp == '\t')
1571 pszTmp++;
1572 if (*pszTmp == '=')
1573 {
1574 pszTmp++;
1575 while (*pszTmp == ' ' || *pszTmp == '\t')
1576 pszTmp++;
1577 break;
1578 }
1579 }
1580 if (!pDescriptor->aNextLines[uStart])
1581 uLast = uStart;
1582 uStart = pDescriptor->aNextLines[uStart];
1583 }
1584 if (uStart)
1585 {
1586 if (pszValue)
1587 {
1588 /* Key already exists, replace existing value. */
1589 size_t cbOldVal = strlen(pszTmp);
1590 size_t cbNewVal = strlen(pszValue);
1591 ssize_t cbDiff = cbNewVal - cbOldVal;
1592 /* Check for buffer overflow. */
1593 if ( pDescriptor->aLines[pDescriptor->cLines]
1594 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
1595 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
1596
1597 memmove(pszTmp + cbNewVal, pszTmp + cbOldVal,
1598 pDescriptor->aLines[pDescriptor->cLines] - pszTmp - cbOldVal);
1599 memcpy(pszTmp, pszValue, cbNewVal + 1);
1600 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1601 pDescriptor->aLines[i] += cbDiff;
1602 }
1603 else
1604 {
1605 memmove(pDescriptor->aLines[uStart], pDescriptor->aLines[uStart+1],
1606 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uStart+1] + 1);
1607 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1608 {
1609 pDescriptor->aLines[i-1] = pDescriptor->aLines[i];
1610 if (pDescriptor->aNextLines[i])
1611 pDescriptor->aNextLines[i-1] = pDescriptor->aNextLines[i] - 1;
1612 else
1613 pDescriptor->aNextLines[i-1] = 0;
1614 }
1615 pDescriptor->cLines--;
1616 /* Adjust starting line numbers of following descriptor sections. */
1617 if (uStart < pDescriptor->uFirstExtent)
1618 pDescriptor->uFirstExtent--;
1619 if (uStart < pDescriptor->uFirstDDB)
1620 pDescriptor->uFirstDDB--;
1621 }
1622 }
1623 else
1624 {
1625 /* Key doesn't exist, append after the last entry in this category. */
1626 if (!pszValue)
1627 {
1628 /* Key doesn't exist, and it should be removed. Simply a no-op. */
1629 return VINF_SUCCESS;
1630 }
1631 cbKey = strlen(pszKey);
1632 size_t cbValue = strlen(pszValue);
1633 ssize_t cbDiff = cbKey + 1 + cbValue + 1;
1634 /* Check for buffer overflow. */
1635 if ( (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
1636 || ( pDescriptor->aLines[pDescriptor->cLines]
1637 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
1638 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
1639 for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
1640 {
1641 pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
1642 if (pDescriptor->aNextLines[i - 1])
1643 pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
1644 else
1645 pDescriptor->aNextLines[i] = 0;
1646 }
1647 uStart = uLast + 1;
1648 pDescriptor->aNextLines[uLast] = uStart;
1649 pDescriptor->aNextLines[uStart] = 0;
1650 pDescriptor->cLines++;
1651 pszTmp = pDescriptor->aLines[uStart];
1652 memmove(pszTmp + cbDiff, pszTmp,
1653 pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
1654 memcpy(pDescriptor->aLines[uStart], pszKey, cbKey);
1655 pDescriptor->aLines[uStart][cbKey] = '=';
1656 memcpy(pDescriptor->aLines[uStart] + cbKey + 1, pszValue, cbValue + 1);
1657 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1658 pDescriptor->aLines[i] += cbDiff;
1659
1660 /* Adjust starting line numbers of following descriptor sections. */
1661 if (uStart <= pDescriptor->uFirstExtent)
1662 pDescriptor->uFirstExtent++;
1663 if (uStart <= pDescriptor->uFirstDDB)
1664 pDescriptor->uFirstDDB++;
1665 }
1666 pDescriptor->fDirty = true;
1667 return VINF_SUCCESS;
1668}
1669
1670static int vmdkDescBaseGetU32(PVMDKDESCRIPTOR pDescriptor, const char *pszKey,
1671 uint32_t *puValue)
1672{
1673 const char *pszValue;
1674
1675 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
1676 &pszValue))
1677 return VERR_VD_VMDK_VALUE_NOT_FOUND;
1678 return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
1679}
1680
1681static int vmdkDescBaseGetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1682 const char *pszKey, const char **ppszValue)
1683{
1684 const char *pszValue;
1685 char *pszValueUnquoted;
1686
1687 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
1688 &pszValue))
1689 return VERR_VD_VMDK_VALUE_NOT_FOUND;
1690 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
1691 if (RT_FAILURE(rc))
1692 return rc;
1693 *ppszValue = pszValueUnquoted;
1694 return rc;
1695}
1696
1697static int vmdkDescBaseSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1698 const char *pszKey, const char *pszValue)
1699{
1700 char *pszValueQuoted;
1701
1702 RTStrAPrintf(&pszValueQuoted, "\"%s\"", pszValue);
1703 if (!pszValueQuoted)
1704 return VERR_NO_STR_MEMORY;
1705 int rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey,
1706 pszValueQuoted);
1707 RTStrFree(pszValueQuoted);
1708 return rc;
1709}
1710
1711static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage,
1712 PVMDKDESCRIPTOR pDescriptor)
1713{
1714 unsigned uEntry = pDescriptor->uFirstExtent;
1715 ssize_t cbDiff;
1716
1717 if (!uEntry)
1718 return;
1719
1720 cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
1721 /* Move everything including \0 in the entry marking the end of buffer. */
1722 memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
1723 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
1724 for (unsigned i = uEntry + 1; i <= pDescriptor->cLines; i++)
1725 {
1726 pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff;
1727 if (pDescriptor->aNextLines[i])
1728 pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1;
1729 else
1730 pDescriptor->aNextLines[i - 1] = 0;
1731 }
1732 pDescriptor->cLines--;
1733 if (pDescriptor->uFirstDDB)
1734 pDescriptor->uFirstDDB--;
1735
1736 return;
1737}
1738
1739static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1740 VMDKACCESS enmAccess, uint64_t cNominalSectors,
1741 VMDKETYPE enmType, const char *pszBasename,
1742 uint64_t uSectorOffset)
1743{
1744 static const char *apszAccess[] = { "NOACCESS", "RDONLY", "RW" };
1745 static const char *apszType[] = { "", "SPARSE", "FLAT", "ZERO", "VMFS" };
1746 char *pszTmp;
1747 unsigned uStart = pDescriptor->uFirstExtent, uLast = 0;
1748 char szExt[1024];
1749 ssize_t cbDiff;
1750
1751 Assert((unsigned)enmAccess < RT_ELEMENTS(apszAccess));
1752 Assert((unsigned)enmType < RT_ELEMENTS(apszType));
1753
1754 /* Find last entry in extent description. */
1755 while (uStart)
1756 {
1757 if (!pDescriptor->aNextLines[uStart])
1758 uLast = uStart;
1759 uStart = pDescriptor->aNextLines[uStart];
1760 }
1761
1762 if (enmType == VMDKETYPE_ZERO)
1763 {
1764 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s ", apszAccess[enmAccess],
1765 cNominalSectors, apszType[enmType]);
1766 }
1767 else if (enmType == VMDKETYPE_FLAT)
1768 {
1769 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\" %llu",
1770 apszAccess[enmAccess], cNominalSectors,
1771 apszType[enmType], pszBasename, uSectorOffset);
1772 }
1773 else
1774 {
1775 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\"",
1776 apszAccess[enmAccess], cNominalSectors,
1777 apszType[enmType], pszBasename);
1778 }
1779 cbDiff = strlen(szExt) + 1;
1780
1781 /* Check for buffer overflow. */
1782 if ( (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
1783 || ( pDescriptor->aLines[pDescriptor->cLines]
1784 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
1785 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
1786
1787 for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
1788 {
1789 pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
1790 if (pDescriptor->aNextLines[i - 1])
1791 pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
1792 else
1793 pDescriptor->aNextLines[i] = 0;
1794 }
1795 uStart = uLast + 1;
1796 pDescriptor->aNextLines[uLast] = uStart;
1797 pDescriptor->aNextLines[uStart] = 0;
1798 pDescriptor->cLines++;
1799 pszTmp = pDescriptor->aLines[uStart];
1800 memmove(pszTmp + cbDiff, pszTmp,
1801 pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
1802 memcpy(pDescriptor->aLines[uStart], szExt, cbDiff);
1803 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1804 pDescriptor->aLines[i] += cbDiff;
1805
1806 /* Adjust starting line numbers of following descriptor sections. */
1807 if (uStart <= pDescriptor->uFirstDDB)
1808 pDescriptor->uFirstDDB++;
1809
1810 pDescriptor->fDirty = true;
1811 return VINF_SUCCESS;
1812}
1813
1814static int vmdkDescDDBGetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1815 const char *pszKey, const char **ppszValue)
1816{
1817 const char *pszValue;
1818 char *pszValueUnquoted;
1819
1820 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
1821 &pszValue))
1822 return VERR_VD_VMDK_VALUE_NOT_FOUND;
1823 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
1824 if (RT_FAILURE(rc))
1825 return rc;
1826 *ppszValue = pszValueUnquoted;
1827 return rc;
1828}
1829
1830static int vmdkDescDDBGetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1831 const char *pszKey, uint32_t *puValue)
1832{
1833 const char *pszValue;
1834 char *pszValueUnquoted;
1835
1836 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
1837 &pszValue))
1838 return VERR_VD_VMDK_VALUE_NOT_FOUND;
1839 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
1840 if (RT_FAILURE(rc))
1841 return rc;
1842 rc = RTStrToUInt32Ex(pszValueUnquoted, NULL, 10, puValue);
1843 RTMemTmpFree(pszValueUnquoted);
1844 return rc;
1845}
1846
1847static int vmdkDescDDBGetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1848 const char *pszKey, PRTUUID pUuid)
1849{
1850 const char *pszValue;
1851 char *pszValueUnquoted;
1852
1853 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
1854 &pszValue))
1855 return VERR_VD_VMDK_VALUE_NOT_FOUND;
1856 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
1857 if (RT_FAILURE(rc))
1858 return rc;
1859 rc = RTUuidFromStr(pUuid, pszValueUnquoted);
1860 RTMemTmpFree(pszValueUnquoted);
1861 return rc;
1862}
1863
1864static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1865 const char *pszKey, const char *pszVal)
1866{
1867 int rc;
1868 char *pszValQuoted;
1869
1870 if (pszVal)
1871 {
1872 RTStrAPrintf(&pszValQuoted, "\"%s\"", pszVal);
1873 if (!pszValQuoted)
1874 return VERR_NO_STR_MEMORY;
1875 }
1876 else
1877 pszValQuoted = NULL;
1878 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
1879 pszValQuoted);
1880 if (pszValQuoted)
1881 RTStrFree(pszValQuoted);
1882 return rc;
1883}
1884
1885static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1886 const char *pszKey, PCRTUUID pUuid)
1887{
1888 char *pszUuid;
1889
1890 RTStrAPrintf(&pszUuid, "\"%RTuuid\"", pUuid);
1891 if (!pszUuid)
1892 return VERR_NO_STR_MEMORY;
1893 int rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
1894 pszUuid);
1895 RTStrFree(pszUuid);
1896 return rc;
1897}
1898
1899static int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1900 const char *pszKey, uint32_t uValue)
1901{
1902 char *pszValue;
1903
1904 RTStrAPrintf(&pszValue, "\"%d\"", uValue);
1905 if (!pszValue)
1906 return VERR_NO_STR_MEMORY;
1907 int rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
1908 pszValue);
1909 RTStrFree(pszValue);
1910 return rc;
1911}
1912
1913static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
1914 size_t cbDescData,
1915 PVMDKDESCRIPTOR pDescriptor)
1916{
1917 int rc = VINF_SUCCESS;
1918 unsigned cLine = 0, uLastNonEmptyLine = 0;
1919 char *pTmp = pDescData;
1920
1921 pDescriptor->cbDescAlloc = cbDescData;
1922 while (*pTmp != '\0')
1923 {
1924 pDescriptor->aLines[cLine++] = pTmp;
1925 if (cLine >= VMDK_DESCRIPTOR_LINES_MAX)
1926 {
1927 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
1928 goto out;
1929 }
1930
1931 while (*pTmp != '\0' && *pTmp != '\n')
1932 {
1933 if (*pTmp == '\r')
1934 {
1935 if (*(pTmp + 1) != '\n')
1936 {
1937 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: unsupported end of line in descriptor in '%s'"), pImage->pszFilename);
1938 goto out;
1939 }
1940 else
1941 {
1942 /* Get rid of CR character. */
1943 *pTmp = '\0';
1944 }
1945 }
1946 pTmp++;
1947 }
1948 /* Get rid of LF character. */
1949 if (*pTmp == '\n')
1950 {
1951 *pTmp = '\0';
1952 pTmp++;
1953 }
1954 }
1955 pDescriptor->cLines = cLine;
1956 /* Pointer right after the end of the used part of the buffer. */
1957 pDescriptor->aLines[cLine] = pTmp;
1958
1959 if ( strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile")
1960 && strcmp(pDescriptor->aLines[0], "# Disk Descriptor File"))
1961 {
1962 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename);
1963 goto out;
1964 }
1965
1966 /* Initialize those, because we need to be able to reopen an image. */
1967 pDescriptor->uFirstDesc = 0;
1968 pDescriptor->uFirstExtent = 0;
1969 pDescriptor->uFirstDDB = 0;
1970 for (unsigned i = 0; i < cLine; i++)
1971 {
1972 if (*pDescriptor->aLines[i] != '#' && *pDescriptor->aLines[i] != '\0')
1973 {
1974 if ( !strncmp(pDescriptor->aLines[i], "RW", 2)
1975 || !strncmp(pDescriptor->aLines[i], "RDONLY", 6)
1976 || !strncmp(pDescriptor->aLines[i], "NOACCESS", 8) )
1977 {
1978 /* An extent descriptor. */
1979 if (!pDescriptor->uFirstDesc || pDescriptor->uFirstDDB)
1980 {
1981 /* Incorrect ordering of entries. */
1982 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
1983 goto out;
1984 }
1985 if (!pDescriptor->uFirstExtent)
1986 {
1987 pDescriptor->uFirstExtent = i;
1988 uLastNonEmptyLine = 0;
1989 }
1990 }
1991 else if (!strncmp(pDescriptor->aLines[i], "ddb.", 4))
1992 {
1993 /* A disk database entry. */
1994 if (!pDescriptor->uFirstDesc || !pDescriptor->uFirstExtent)
1995 {
1996 /* Incorrect ordering of entries. */
1997 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
1998 goto out;
1999 }
2000 if (!pDescriptor->uFirstDDB)
2001 {
2002 pDescriptor->uFirstDDB = i;
2003 uLastNonEmptyLine = 0;
2004 }
2005 }
2006 else
2007 {
2008 /* A normal entry. */
2009 if (pDescriptor->uFirstExtent || pDescriptor->uFirstDDB)
2010 {
2011 /* Incorrect ordering of entries. */
2012 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
2013 goto out;
2014 }
2015 if (!pDescriptor->uFirstDesc)
2016 {
2017 pDescriptor->uFirstDesc = i;
2018 uLastNonEmptyLine = 0;
2019 }
2020 }
2021 if (uLastNonEmptyLine)
2022 pDescriptor->aNextLines[uLastNonEmptyLine] = i;
2023 uLastNonEmptyLine = i;
2024 }
2025 }
2026
2027out:
2028 return rc;
2029}
2030
2031static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage,
2032 PCVDGEOMETRY pPCHSGeometry)
2033{
2034 int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2035 VMDK_DDB_GEO_PCHS_CYLINDERS,
2036 pPCHSGeometry->cCylinders);
2037 if (RT_FAILURE(rc))
2038 return rc;
2039 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2040 VMDK_DDB_GEO_PCHS_HEADS,
2041 pPCHSGeometry->cHeads);
2042 if (RT_FAILURE(rc))
2043 return rc;
2044 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2045 VMDK_DDB_GEO_PCHS_SECTORS,
2046 pPCHSGeometry->cSectors);
2047 return rc;
2048}
2049
2050static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage,
2051 PCVDGEOMETRY pLCHSGeometry)
2052{
2053 int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2054 VMDK_DDB_GEO_LCHS_CYLINDERS,
2055 pLCHSGeometry->cCylinders);
2056 if (RT_FAILURE(rc))
2057 return rc;
2058 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2059 VMDK_DDB_GEO_LCHS_HEADS,
2060
2061 pLCHSGeometry->cHeads);
2062 if (RT_FAILURE(rc))
2063 return rc;
2064 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2065 VMDK_DDB_GEO_LCHS_SECTORS,
2066 pLCHSGeometry->cSectors);
2067 return rc;
2068}
2069
2070static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData,
2071 size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
2072{
2073 int rc;
2074
2075 pDescriptor->uFirstDesc = 0;
2076 pDescriptor->uFirstExtent = 0;
2077 pDescriptor->uFirstDDB = 0;
2078 pDescriptor->cLines = 0;
2079 pDescriptor->cbDescAlloc = cbDescData;
2080 pDescriptor->fDirty = false;
2081 pDescriptor->aLines[pDescriptor->cLines] = pDescData;
2082 memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
2083
2084 rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile");
2085 if (RT_FAILURE(rc))
2086 goto out;
2087 rc = vmdkDescInitStr(pImage, pDescriptor, "version=1");
2088 if (RT_FAILURE(rc))
2089 goto out;
2090 pDescriptor->uFirstDesc = pDescriptor->cLines - 1;
2091 rc = vmdkDescInitStr(pImage, pDescriptor, "");
2092 if (RT_FAILURE(rc))
2093 goto out;
2094 rc = vmdkDescInitStr(pImage, pDescriptor, "# Extent description");
2095 if (RT_FAILURE(rc))
2096 goto out;
2097 rc = vmdkDescInitStr(pImage, pDescriptor, "NOACCESS 0 ZERO ");
2098 if (RT_FAILURE(rc))
2099 goto out;
2100 pDescriptor->uFirstExtent = pDescriptor->cLines - 1;
2101 rc = vmdkDescInitStr(pImage, pDescriptor, "");
2102 if (RT_FAILURE(rc))
2103 goto out;
2104 /* The trailing space is created by VMware, too. */
2105 rc = vmdkDescInitStr(pImage, pDescriptor, "# The disk Data Base ");
2106 if (RT_FAILURE(rc))
2107 goto out;
2108 rc = vmdkDescInitStr(pImage, pDescriptor, "#DDB");
2109 if (RT_FAILURE(rc))
2110 goto out;
2111 rc = vmdkDescInitStr(pImage, pDescriptor, "");
2112 if (RT_FAILURE(rc))
2113 goto out;
2114 rc = vmdkDescInitStr(pImage, pDescriptor, "ddb.virtualHWVersion = \"4\"");
2115 if (RT_FAILURE(rc))
2116 goto out;
2117 pDescriptor->uFirstDDB = pDescriptor->cLines - 1;
2118
2119 /* Now that the framework is in place, use the normal functions to insert
2120 * the remaining keys. */
2121 char szBuf[9];
2122 RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32());
2123 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
2124 "CID", szBuf);
2125 if (RT_FAILURE(rc))
2126 goto out;
2127 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
2128 "parentCID", "ffffffff");
2129 if (RT_FAILURE(rc))
2130 goto out;
2131
2132 rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide");
2133 if (RT_FAILURE(rc))
2134 goto out;
2135
2136out:
2137 return rc;
2138}
2139
2140static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData,
2141 size_t cbDescData)
2142{
2143 int rc;
2144 unsigned cExtents;
2145 unsigned uLine;
2146 unsigned i;
2147
2148 rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData,
2149 &pImage->Descriptor);
2150 if (RT_FAILURE(rc))
2151 return rc;
2152
2153 /* Check version, must be 1. */
2154 uint32_t uVersion;
2155 rc = vmdkDescBaseGetU32(&pImage->Descriptor, "version", &uVersion);
2156 if (RT_FAILURE(rc))
2157 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error finding key 'version' in descriptor in '%s'"), pImage->pszFilename);
2158 if (uVersion != 1)
2159 return vmdkError(pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor in '%s'"), pImage->pszFilename);
2160
2161 /* Get image creation type and determine image flags. */
2162 const char *pszCreateType = NULL; /* initialized to make gcc shut up */
2163 rc = vmdkDescBaseGetStr(pImage, &pImage->Descriptor, "createType",
2164 &pszCreateType);
2165 if (RT_FAILURE(rc))
2166 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot get image type from descriptor in '%s'"), pImage->pszFilename);
2167 if ( !strcmp(pszCreateType, "twoGbMaxExtentSparse")
2168 || !strcmp(pszCreateType, "twoGbMaxExtentFlat"))
2169 pImage->uImageFlags |= VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
2170 else if ( !strcmp(pszCreateType, "partitionedDevice")
2171 || !strcmp(pszCreateType, "fullDevice"))
2172 pImage->uImageFlags |= VD_VMDK_IMAGE_FLAGS_RAWDISK;
2173 else if (!strcmp(pszCreateType, "streamOptimized"))
2174 pImage->uImageFlags |= VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED;
2175 else if (!strcmp(pszCreateType, "vmfs"))
2176 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_ESX;
2177 RTStrFree((char *)(void *)pszCreateType);
2178
2179 /* Count the number of extent config entries. */
2180 for (uLine = pImage->Descriptor.uFirstExtent, cExtents = 0;
2181 uLine != 0;
2182 uLine = pImage->Descriptor.aNextLines[uLine], cExtents++)
2183 /* nothing */;
2184
2185 if (!pImage->pDescData && cExtents != 1)
2186 {
2187 /* Monolithic image, must have only one extent (already opened). */
2188 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image may only have one extent in '%s'"), pImage->pszFilename);
2189 }
2190
2191 if (pImage->pDescData)
2192 {
2193 /* Non-monolithic image, extents need to be allocated. */
2194 rc = vmdkCreateExtents(pImage, cExtents);
2195 if (RT_FAILURE(rc))
2196 return rc;
2197 }
2198
2199 for (i = 0, uLine = pImage->Descriptor.uFirstExtent;
2200 i < cExtents; i++, uLine = pImage->Descriptor.aNextLines[uLine])
2201 {
2202 char *pszLine = pImage->Descriptor.aLines[uLine];
2203
2204 /* Access type of the extent. */
2205 if (!strncmp(pszLine, "RW", 2))
2206 {
2207 pImage->pExtents[i].enmAccess = VMDKACCESS_READWRITE;
2208 pszLine += 2;
2209 }
2210 else if (!strncmp(pszLine, "RDONLY", 6))
2211 {
2212 pImage->pExtents[i].enmAccess = VMDKACCESS_READONLY;
2213 pszLine += 6;
2214 }
2215 else if (!strncmp(pszLine, "NOACCESS", 8))
2216 {
2217 pImage->pExtents[i].enmAccess = VMDKACCESS_NOACCESS;
2218 pszLine += 8;
2219 }
2220 else
2221 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2222 if (*pszLine++ != ' ')
2223 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2224
2225 /* Nominal size of the extent. */
2226 rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
2227 &pImage->pExtents[i].cNominalSectors);
2228 if (RT_FAILURE(rc))
2229 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2230 if (*pszLine++ != ' ')
2231 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2232
2233 /* Type of the extent. */
2234#ifdef VBOX_WITH_VMDK_ESX
2235 /** @todo Add the ESX extent types. Not necessary for now because
2236 * the ESX extent types are only used inside an ESX server. They are
2237 * automatically converted if the VMDK is exported. */
2238#endif /* VBOX_WITH_VMDK_ESX */
2239 if (!strncmp(pszLine, "SPARSE", 6))
2240 {
2241 pImage->pExtents[i].enmType = VMDKETYPE_HOSTED_SPARSE;
2242 pszLine += 6;
2243 }
2244 else if (!strncmp(pszLine, "FLAT", 4))
2245 {
2246 pImage->pExtents[i].enmType = VMDKETYPE_FLAT;
2247 pszLine += 4;
2248 }
2249 else if (!strncmp(pszLine, "ZERO", 4))
2250 {
2251 pImage->pExtents[i].enmType = VMDKETYPE_ZERO;
2252 pszLine += 4;
2253 }
2254 else if (!strncmp(pszLine, "VMFS", 4))
2255 {
2256 pImage->pExtents[i].enmType = VMDKETYPE_VMFS;
2257 pszLine += 4;
2258 }
2259 else
2260 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2261
2262 if (pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
2263 {
2264 /* This one has no basename or offset. */
2265 if (*pszLine == ' ')
2266 pszLine++;
2267 if (*pszLine != '\0')
2268 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2269 pImage->pExtents[i].pszBasename = NULL;
2270 }
2271 else
2272 {
2273 /* All other extent types have basename and optional offset. */
2274 if (*pszLine++ != ' ')
2275 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2276
2277 /* Basename of the image. Surrounded by quotes. */
2278 char *pszBasename;
2279 rc = vmdkStringUnquote(pImage, pszLine, &pszBasename, &pszLine);
2280 if (RT_FAILURE(rc))
2281 return rc;
2282 pImage->pExtents[i].pszBasename = pszBasename;
2283 if (*pszLine == ' ')
2284 {
2285 pszLine++;
2286 if (*pszLine != '\0')
2287 {
2288 /* Optional offset in extent specified. */
2289 rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
2290 &pImage->pExtents[i].uSectorOffset);
2291 if (RT_FAILURE(rc))
2292 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2293 }
2294 }
2295
2296 if (*pszLine != '\0')
2297 return vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
2298 }
2299 }
2300
2301 /* Determine PCHS geometry (autogenerate if necessary). */
2302 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2303 VMDK_DDB_GEO_PCHS_CYLINDERS,
2304 &pImage->PCHSGeometry.cCylinders);
2305 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2306 pImage->PCHSGeometry.cCylinders = 0;
2307 else if (RT_FAILURE(rc))
2308 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
2309 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2310 VMDK_DDB_GEO_PCHS_HEADS,
2311 &pImage->PCHSGeometry.cHeads);
2312 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2313 pImage->PCHSGeometry.cHeads = 0;
2314 else if (RT_FAILURE(rc))
2315 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
2316 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2317 VMDK_DDB_GEO_PCHS_SECTORS,
2318 &pImage->PCHSGeometry.cSectors);
2319 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2320 pImage->PCHSGeometry.cSectors = 0;
2321 else if (RT_FAILURE(rc))
2322 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
2323 if ( pImage->PCHSGeometry.cCylinders == 0
2324 || pImage->PCHSGeometry.cHeads == 0
2325 || pImage->PCHSGeometry.cHeads > 16
2326 || pImage->PCHSGeometry.cSectors == 0
2327 || pImage->PCHSGeometry.cSectors > 63)
2328 {
2329 /* Mark PCHS geometry as not yet valid (can't do the calculation here
2330 * as the total image size isn't known yet). */
2331 pImage->PCHSGeometry.cCylinders = 0;
2332 pImage->PCHSGeometry.cHeads = 16;
2333 pImage->PCHSGeometry.cSectors = 63;
2334 }
2335
2336 /* Determine LCHS geometry (set to 0 if not specified). */
2337 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2338 VMDK_DDB_GEO_LCHS_CYLINDERS,
2339 &pImage->LCHSGeometry.cCylinders);
2340 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2341 pImage->LCHSGeometry.cCylinders = 0;
2342 else if (RT_FAILURE(rc))
2343 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
2344 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2345 VMDK_DDB_GEO_LCHS_HEADS,
2346 &pImage->LCHSGeometry.cHeads);
2347 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2348 pImage->LCHSGeometry.cHeads = 0;
2349 else if (RT_FAILURE(rc))
2350 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
2351 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2352 VMDK_DDB_GEO_LCHS_SECTORS,
2353 &pImage->LCHSGeometry.cSectors);
2354 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2355 pImage->LCHSGeometry.cSectors = 0;
2356 else if (RT_FAILURE(rc))
2357 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
2358 if ( pImage->LCHSGeometry.cCylinders == 0
2359 || pImage->LCHSGeometry.cHeads == 0
2360 || pImage->LCHSGeometry.cSectors == 0)
2361 {
2362 pImage->LCHSGeometry.cCylinders = 0;
2363 pImage->LCHSGeometry.cHeads = 0;
2364 pImage->LCHSGeometry.cSectors = 0;
2365 }
2366
2367 /* Get image UUID. */
2368 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_IMAGE_UUID,
2369 &pImage->ImageUuid);
2370 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2371 {
2372 /* Image without UUID. Probably created by VMware and not yet used
2373 * by VirtualBox. Can only be added for images opened in read/write
2374 * mode, so don't bother producing a sensible UUID otherwise. */
2375 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2376 RTUuidClear(&pImage->ImageUuid);
2377 else
2378 {
2379 rc = RTUuidCreate(&pImage->ImageUuid);
2380 if (RT_FAILURE(rc))
2381 return rc;
2382 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2383 VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
2384 if (RT_FAILURE(rc))
2385 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
2386 }
2387 }
2388 else if (RT_FAILURE(rc))
2389 return rc;
2390
2391 /* Get image modification UUID. */
2392 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
2393 VMDK_DDB_MODIFICATION_UUID,
2394 &pImage->ModificationUuid);
2395 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2396 {
2397 /* Image without UUID. Probably created by VMware and not yet used
2398 * by VirtualBox. Can only be added for images opened in read/write
2399 * mode, so don't bother producing a sensible UUID otherwise. */
2400 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2401 RTUuidClear(&pImage->ModificationUuid);
2402 else
2403 {
2404 rc = RTUuidCreate(&pImage->ModificationUuid);
2405 if (RT_FAILURE(rc))
2406 return rc;
2407 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2408 VMDK_DDB_MODIFICATION_UUID,
2409 &pImage->ModificationUuid);
2410 if (RT_FAILURE(rc))
2411 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename);
2412 }
2413 }
2414 else if (RT_FAILURE(rc))
2415 return rc;
2416
2417 /* Get UUID of parent image. */
2418 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_PARENT_UUID,
2419 &pImage->ParentUuid);
2420 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2421 {
2422 /* Image without UUID. Probably created by VMware and not yet used
2423 * by VirtualBox. Can only be added for images opened in read/write
2424 * mode, so don't bother producing a sensible UUID otherwise. */
2425 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2426 RTUuidClear(&pImage->ParentUuid);
2427 else
2428 {
2429 rc = RTUuidClear(&pImage->ParentUuid);
2430 if (RT_FAILURE(rc))
2431 return rc;
2432 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2433 VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
2434 if (RT_FAILURE(rc))
2435 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent UUID in descriptor in '%s'"), pImage->pszFilename);
2436 }
2437 }
2438 else if (RT_FAILURE(rc))
2439 return rc;
2440
2441 /* Get parent image modification UUID. */
2442 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
2443 VMDK_DDB_PARENT_MODIFICATION_UUID,
2444 &pImage->ParentModificationUuid);
2445 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
2446 {
2447 /* Image without UUID. Probably created by VMware and not yet used
2448 * by VirtualBox. Can only be added for images opened in read/write
2449 * mode, so don't bother producing a sensible UUID otherwise. */
2450 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2451 RTUuidClear(&pImage->ParentModificationUuid);
2452 else
2453 {
2454 rc = RTUuidCreate(&pImage->ParentModificationUuid);
2455 if (RT_FAILURE(rc))
2456 return rc;
2457 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2458 VMDK_DDB_PARENT_MODIFICATION_UUID,
2459 &pImage->ParentModificationUuid);
2460 if (RT_FAILURE(rc))
2461 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in descriptor in '%s'"), pImage->pszFilename);
2462 }
2463 }
2464 else if (RT_FAILURE(rc))
2465 return rc;
2466
2467 return VINF_SUCCESS;
2468}
2469
2470/**
2471 * Internal : Prepares the descriptor to write to the image.
2472 */
2473static int vmdkDescriptorPrepare(PVMDKIMAGE pImage, uint64_t cbLimit,
2474 void **ppvData, size_t *pcbData)
2475{
2476 int rc = VINF_SUCCESS;
2477
2478 /*
2479 * Allocate temporary descriptor buffer.
2480 * In case there is no limit allocate a default
2481 * and increase if required.
2482 */
2483 size_t cbDescriptor = cbLimit ? cbLimit : 4 * _1K;
2484 char *pszDescriptor = (char *)RTMemAllocZ(cbDescriptor);
2485 unsigned offDescriptor = 0;
2486
2487 if (!pszDescriptor)
2488 return VERR_NO_MEMORY;
2489
2490 for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
2491 {
2492 const char *psz = pImage->Descriptor.aLines[i];
2493 size_t cb = strlen(psz);
2494
2495 /*
2496 * Increase the descriptor if there is no limit and
2497 * there is not enough room left for this line.
2498 */
2499 if (offDescriptor + cb + 1 > cbDescriptor)
2500 {
2501 if (cbLimit)
2502 {
2503 rc = vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
2504 break;
2505 }
2506 else
2507 {
2508 char *pszDescriptorNew = NULL;
2509 LogFlow(("Increasing descriptor cache\n"));
2510
2511 pszDescriptorNew = (char *)RTMemRealloc(pszDescriptor, cbDescriptor + cb + 4 * _1K);
2512 if (!pszDescriptorNew)
2513 {
2514 rc = VERR_NO_MEMORY;
2515 break;
2516 }
2517 pszDescriptor = pszDescriptorNew;
2518 cbDescriptor += cb + 4 * _1K;
2519 }
2520 }
2521
2522 if (cb > 0)
2523 {
2524 memcpy(pszDescriptor + offDescriptor, psz, cb);
2525 offDescriptor += cb;
2526 }
2527
2528 memcpy(pszDescriptor + offDescriptor, "\n", 1);
2529 offDescriptor++;
2530 }
2531
2532 if (RT_SUCCESS(rc))
2533 {
2534 *ppvData = pszDescriptor;
2535 *pcbData = offDescriptor;
2536 }
2537 else if (pszDescriptor)
2538 RTMemFree(pszDescriptor);
2539
2540 return rc;
2541}
2542
2543/**
2544 * Internal: write/update the descriptor part of the image.
2545 */
2546static int vmdkWriteDescriptor(PVMDKIMAGE pImage)
2547{
2548 int rc = VINF_SUCCESS;
2549 uint64_t cbLimit;
2550 uint64_t uOffset;
2551 PVMDKFILE pDescFile;
2552 void *pvDescriptor;
2553 size_t cbDescriptor;
2554
2555 if (pImage->pDescData)
2556 {
2557 /* Separate descriptor file. */
2558 uOffset = 0;
2559 cbLimit = 0;
2560 pDescFile = pImage->pFile;
2561 }
2562 else
2563 {
2564 /* Embedded descriptor file. */
2565 uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector);
2566 cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
2567 pDescFile = pImage->pExtents[0].pFile;
2568 }
2569 /* Bail out if there is no file to write to. */
2570 if (pDescFile == NULL)
2571 return VERR_INVALID_PARAMETER;
2572
2573 rc = vmdkDescriptorPrepare(pImage, cbLimit, &pvDescriptor, &cbDescriptor);
2574 if (RT_SUCCESS(rc))
2575 {
2576 rc = vmdkFileWriteSync(pImage, pDescFile, uOffset, pvDescriptor, cbLimit ? cbLimit : cbDescriptor, NULL);
2577 if (RT_FAILURE(rc))
2578 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
2579
2580 if (RT_SUCCESS(rc) && !cbLimit)
2581 {
2582 rc = vmdkFileSetSize(pImage, pDescFile, cbDescriptor);
2583 if (RT_FAILURE(rc))
2584 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
2585 }
2586
2587 if (RT_SUCCESS(rc))
2588 pImage->Descriptor.fDirty = false;
2589
2590 RTMemFree(pvDescriptor);
2591 }
2592
2593 return rc;
2594}
2595
2596/**
2597 * Internal: write/update the descriptor part of the image - async version.
2598 */
2599static int vmdkWriteDescriptorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
2600{
2601 int rc = VINF_SUCCESS;
2602 uint64_t cbLimit;
2603 uint64_t uOffset;
2604 PVMDKFILE pDescFile;
2605 void *pvDescriptor;
2606 size_t cbDescriptor;
2607
2608 if (pImage->pDescData)
2609 {
2610 /* Separate descriptor file. */
2611 uOffset = 0;
2612 cbLimit = 0;
2613 pDescFile = pImage->pFile;
2614 }
2615 else
2616 {
2617 /* Embedded descriptor file. */
2618 uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector);
2619 cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
2620 pDescFile = pImage->pExtents[0].pFile;
2621 }
2622 /* Bail out if there is no file to write to. */
2623 if (pDescFile == NULL)
2624 return VERR_INVALID_PARAMETER;
2625
2626 rc = vmdkDescriptorPrepare(pImage, cbLimit, &pvDescriptor, &cbDescriptor);
2627 if (RT_SUCCESS(rc))
2628 {
2629 rc = vmdkFileWriteMetaAsync(pImage, pDescFile, uOffset, pvDescriptor, cbLimit ? cbLimit : cbDescriptor, pIoCtx, NULL, NULL);
2630 if ( RT_FAILURE(rc)
2631 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
2632 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
2633 }
2634
2635 if (RT_SUCCESS(rc) && !cbLimit)
2636 {
2637 rc = vmdkFileSetSize(pImage, pDescFile, cbDescriptor);
2638 if (RT_FAILURE(rc))
2639 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
2640 }
2641
2642 if (RT_SUCCESS(rc))
2643 pImage->Descriptor.fDirty = false;
2644
2645 RTMemFree(pvDescriptor);
2646 return rc;
2647
2648}
2649
2650/**
2651 * Internal: validate the consistency check values in a binary header.
2652 */
2653static int vmdkValidateHeader(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, const SparseExtentHeader *pHeader)
2654{
2655 int rc = VINF_SUCCESS;
2656 if (RT_LE2H_U32(pHeader->magicNumber) != VMDK_SPARSE_MAGICNUMBER)
2657 {
2658 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic in sparse extent header in '%s'"), pExtent->pszFullname);
2659 return rc;
2660 }
2661 if (RT_LE2H_U32(pHeader->version) != 1 && RT_LE2H_U32(pHeader->version) != 3)
2662 {
2663 rc = vmdkError(pImage, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: incorrect version in sparse extent header in '%s', not a VMDK 1.0/1.1 conforming file"), pExtent->pszFullname);
2664 return rc;
2665 }
2666 if ( (RT_LE2H_U32(pHeader->flags) & 1)
2667 && ( pHeader->singleEndLineChar != '\n'
2668 || pHeader->nonEndLineChar != ' '
2669 || pHeader->doubleEndLineChar1 != '\r'
2670 || pHeader->doubleEndLineChar2 != '\n') )
2671 {
2672 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname);
2673 return rc;
2674 }
2675 return rc;
2676}
2677
2678/**
2679 * Internal: read metadata belonging to an extent with binary header, i.e.
2680 * as found in monolithic files.
2681 */
2682static int vmdkReadBinaryMetaExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
2683 bool fMagicAlreadyRead)
2684{
2685 SparseExtentHeader Header;
2686 uint64_t cSectorsPerGDE;
2687 uint64_t cbFile = 0;
2688 int rc;
2689
2690 if (!fMagicAlreadyRead)
2691 rc = vmdkFileReadSync(pImage, pExtent->pFile, 0, &Header,
2692 sizeof(Header), NULL);
2693 else
2694 {
2695 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
2696 rc = vmdkFileReadSync(pImage, pExtent->pFile,
2697 RT_OFFSETOF(SparseExtentHeader, version),
2698 &Header.version,
2699 sizeof(Header)
2700 - RT_OFFSETOF(SparseExtentHeader, version),
2701 NULL);
2702 }
2703 AssertRC(rc);
2704 if (RT_FAILURE(rc))
2705 {
2706 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
2707 goto out;
2708 }
2709 rc = vmdkValidateHeader(pImage, pExtent, &Header);
2710 if (RT_FAILURE(rc))
2711 goto out;
2712
2713 if ( RT_LE2H_U32(Header.flags & RT_BIT(17))
2714 && RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
2715 pExtent->fFooter = true;
2716
2717 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2718 || ( pExtent->fFooter
2719 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)))
2720 {
2721 rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbFile);
2722 AssertRC(rc);
2723 if (RT_FAILURE(rc))
2724 {
2725 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname);
2726 goto out;
2727 }
2728 }
2729
2730 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2731 pExtent->uAppendPosition = RT_ALIGN_64(cbFile, 512);
2732
2733 if ( pExtent->fFooter
2734 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2735 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)))
2736 {
2737 /* Read the footer, which comes before the end-of-stream marker. */
2738 rc = vmdkFileReadSync(pImage, pExtent->pFile,
2739 cbFile - 2*512, &Header,
2740 sizeof(Header), NULL);
2741 AssertRC(rc);
2742 if (RT_FAILURE(rc))
2743 {
2744 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading extent footer in '%s'"), pExtent->pszFullname);
2745 goto out;
2746 }
2747 rc = vmdkValidateHeader(pImage, pExtent, &Header);
2748 if (RT_FAILURE(rc))
2749 goto out;
2750 /* Prohibit any writes to this extent. */
2751 pExtent->uAppendPosition = 0;
2752 }
2753
2754 pExtent->uVersion = RT_LE2H_U32(Header.version);
2755 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; /* Just dummy value, changed later. */
2756 pExtent->cSectors = RT_LE2H_U64(Header.capacity);
2757 pExtent->cSectorsPerGrain = RT_LE2H_U64(Header.grainSize);
2758 pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset);
2759 pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize);
2760 if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
2761 {
2762 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
2763 goto out;
2764 }
2765 pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT);
2766 if (RT_LE2H_U32(Header.flags) & RT_BIT(1))
2767 {
2768 pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset);
2769 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
2770 }
2771 else
2772 {
2773 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
2774 pExtent->uSectorRGD = 0;
2775 }
2776 if ( ( pExtent->uSectorGD == VMDK_GD_AT_END
2777 || pExtent->uSectorRGD == VMDK_GD_AT_END)
2778 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2779 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)))
2780 {
2781 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname);
2782 goto out;
2783 }
2784 pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
2785 pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
2786 pExtent->uCompression = RT_LE2H_U16(Header.compressAlgorithm);
2787 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
2788 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
2789 {
2790 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
2791 goto out;
2792 }
2793 pExtent->cSectorsPerGDE = cSectorsPerGDE;
2794 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
2795
2796 /* Fix up the number of descriptor sectors, as some flat images have
2797 * really just one, and this causes failures when inserting the UUID
2798 * values and other extra information. */
2799 if (pExtent->cDescriptorSectors != 0 && pExtent->cDescriptorSectors < 4)
2800 {
2801 /* Do it the easy way - just fix it for flat images which have no
2802 * other complicated metadata which needs space too. */
2803 if ( pExtent->uDescriptorSector + 4 < pExtent->cOverheadSectors
2804 && pExtent->cGTEntries * pExtent->cGDEntries == 0)
2805 pExtent->cDescriptorSectors = 4;
2806 }
2807
2808out:
2809 if (RT_FAILURE(rc))
2810 vmdkFreeExtentData(pImage, pExtent, false);
2811
2812 return rc;
2813}
2814
2815/**
2816 * Internal: read additional metadata belonging to an extent. For those
2817 * extents which have no additional metadata just verify the information.
2818 */
2819static int vmdkReadMetaExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
2820{
2821 int rc = VINF_SUCCESS;
2822
2823/* disabled the check as there are too many truncated vmdk images out there */
2824#ifdef VBOX_WITH_VMDK_STRICT_SIZE_CHECK
2825 uint64_t cbExtentSize;
2826 /* The image must be a multiple of a sector in size and contain the data
2827 * area (flat images only). If not, it means the image is at least
2828 * truncated, or even seriously garbled. */
2829 rc = vmdkFileGetSize(pImage, pExtent->pFile, &cbExtentSize);
2830 if (RT_FAILURE(rc))
2831 {
2832 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
2833 goto out;
2834 }
2835 if ( cbExtentSize != RT_ALIGN_64(cbExtentSize, 512)
2836 && (pExtent->enmType != VMDKETYPE_FLAT || pExtent->cNominalSectors + pExtent->uSectorOffset > VMDK_BYTE2SECTOR(cbExtentSize)))
2837 {
2838 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: file size is not a multiple of 512 in '%s', file is truncated or otherwise garbled"), pExtent->pszFullname);
2839 goto out;
2840 }
2841#endif /* VBOX_WITH_VMDK_STRICT_SIZE_CHECK */
2842 if (pExtent->enmType != VMDKETYPE_HOSTED_SPARSE)
2843 goto out;
2844
2845 /* The spec says that this must be a power of two and greater than 8,
2846 * but probably they meant not less than 8. */
2847 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))
2848 || pExtent->cSectorsPerGrain < 8)
2849 {
2850 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
2851 goto out;
2852 }
2853
2854 /* This code requires that a grain table must hold a power of two multiple
2855 * of the number of entries per GT cache entry. */
2856 if ( (pExtent->cGTEntries & (pExtent->cGTEntries - 1))
2857 || pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE)
2858 {
2859 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);
2860 goto out;
2861 }
2862
2863 rc = vmdkAllocStreamBuffers(pImage, pExtent);
2864 if (RT_FAILURE(rc))
2865 goto out;
2866
2867 /* Prohibit any writes to this streamOptimized extent. */
2868 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
2869 pExtent->uAppendPosition = 0;
2870
2871 if ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
2872 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2873 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
2874 rc = vmdkReadGrainDirectory(pImage, pExtent);
2875 else
2876 {
2877 pExtent->uGrainSectorAbs = pExtent->cOverheadSectors;
2878 pExtent->cbGrainStreamRead = 0;
2879 }
2880
2881out:
2882 if (RT_FAILURE(rc))
2883 vmdkFreeExtentData(pImage, pExtent, false);
2884
2885 return rc;
2886}
2887
2888/**
2889 * Internal: write/update the metadata for a sparse extent.
2890 */
2891static int vmdkWriteMetaSparseExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
2892 uint64_t uOffset)
2893{
2894 SparseExtentHeader Header;
2895
2896 memset(&Header, '\0', sizeof(Header));
2897 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
2898 Header.version = RT_H2LE_U32(pExtent->uVersion);
2899 Header.flags = RT_H2LE_U32(RT_BIT(0));
2900 if (pExtent->pRGD)
2901 Header.flags |= RT_H2LE_U32(RT_BIT(1));
2902 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
2903 Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17));
2904 Header.capacity = RT_H2LE_U64(pExtent->cSectors);
2905 Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
2906 Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector);
2907 Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
2908 Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
2909 if (pExtent->fFooter && uOffset == 0)
2910 {
2911 if (pExtent->pRGD)
2912 {
2913 Assert(pExtent->uSectorRGD);
2914 Header.rgdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
2915 Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
2916 }
2917 else
2918 {
2919 Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
2920 }
2921 }
2922 else
2923 {
2924 if (pExtent->pRGD)
2925 {
2926 Assert(pExtent->uSectorRGD);
2927 Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
2928 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
2929 }
2930 else
2931 {
2932 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
2933 }
2934 }
2935 Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
2936 Header.uncleanShutdown = pExtent->fUncleanShutdown;
2937 Header.singleEndLineChar = '\n';
2938 Header.nonEndLineChar = ' ';
2939 Header.doubleEndLineChar1 = '\r';
2940 Header.doubleEndLineChar2 = '\n';
2941 Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
2942
2943 int rc = vmdkFileWriteSync(pImage, pExtent->pFile, uOffset, &Header, sizeof(Header), NULL);
2944 AssertRC(rc);
2945 if (RT_FAILURE(rc))
2946 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname);
2947 return rc;
2948}
2949
2950/**
2951 * Internal: write/update the metadata for a sparse extent - async version.
2952 */
2953static int vmdkWriteMetaSparseExtentAsync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
2954 uint64_t uOffset, PVDIOCTX pIoCtx)
2955{
2956 SparseExtentHeader Header;
2957
2958 memset(&Header, '\0', sizeof(Header));
2959 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
2960 Header.version = RT_H2LE_U32(pExtent->uVersion);
2961 Header.flags = RT_H2LE_U32(RT_BIT(0));
2962 if (pExtent->pRGD)
2963 Header.flags |= RT_H2LE_U32(RT_BIT(1));
2964 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
2965 Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17));
2966 Header.capacity = RT_H2LE_U64(pExtent->cSectors);
2967 Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
2968 Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector);
2969 Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
2970 Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
2971 if (pExtent->fFooter && uOffset == 0)
2972 {
2973 if (pExtent->pRGD)
2974 {
2975 Assert(pExtent->uSectorRGD);
2976 Header.rgdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
2977 Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
2978 }
2979 else
2980 {
2981 Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
2982 }
2983 }
2984 else
2985 {
2986 if (pExtent->pRGD)
2987 {
2988 Assert(pExtent->uSectorRGD);
2989 Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
2990 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
2991 }
2992 else
2993 {
2994 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
2995 }
2996 }
2997 Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
2998 Header.uncleanShutdown = pExtent->fUncleanShutdown;
2999 Header.singleEndLineChar = '\n';
3000 Header.nonEndLineChar = ' ';
3001 Header.doubleEndLineChar1 = '\r';
3002 Header.doubleEndLineChar2 = '\n';
3003 Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
3004
3005 int rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
3006 uOffset, &Header, sizeof(Header),
3007 pIoCtx, NULL, NULL);
3008 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
3009 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname);
3010 return rc;
3011}
3012
3013#ifdef VBOX_WITH_VMDK_ESX
3014/**
3015 * Internal: unused code to read the metadata of a sparse ESX extent.
3016 *
3017 * Such extents never leave ESX server, so this isn't ever used.
3018 */
3019static int vmdkReadMetaESXSparseExtent(PVMDKEXTENT pExtent)
3020{
3021 COWDisk_Header Header;
3022 uint64_t cSectorsPerGDE;
3023
3024 int rc = vmdkFileReadSync(pImage, pExtent->pFile, 0, &Header, sizeof(Header), NULL);
3025 AssertRC(rc);
3026 if (RT_FAILURE(rc))
3027 goto out;
3028 if ( RT_LE2H_U32(Header.magicNumber) != VMDK_ESX_SPARSE_MAGICNUMBER
3029 || RT_LE2H_U32(Header.version) != 1
3030 || RT_LE2H_U32(Header.flags) != 3)
3031 {
3032 rc = VERR_VD_VMDK_INVALID_HEADER;
3033 goto out;
3034 }
3035 pExtent->enmType = VMDKETYPE_ESX_SPARSE;
3036 pExtent->cSectors = RT_LE2H_U32(Header.numSectors);
3037 pExtent->cSectorsPerGrain = RT_LE2H_U32(Header.grainSize);
3038 /* The spec says that this must be between 1 sector and 1MB. This code
3039 * assumes it's a power of two, so check that requirement, too. */
3040 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))
3041 || pExtent->cSectorsPerGrain == 0
3042 || pExtent->cSectorsPerGrain > 2048)
3043 {
3044 rc = VERR_VD_VMDK_INVALID_HEADER;
3045 goto out;
3046 }
3047 pExtent->uDescriptorSector = 0;
3048 pExtent->cDescriptorSectors = 0;
3049 pExtent->uSectorGD = RT_LE2H_U32(Header.gdOffset);
3050 pExtent->uSectorRGD = 0;
3051 pExtent->cOverheadSectors = 0;
3052 pExtent->cGTEntries = 4096;
3053 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
3054 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
3055 {
3056 rc = VERR_VD_VMDK_INVALID_HEADER;
3057 goto out;
3058 }
3059 pExtent->cSectorsPerGDE = cSectorsPerGDE;
3060 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
3061 if (pExtent->cGDEntries != RT_LE2H_U32(Header.numGDEntries))
3062 {
3063 /* Inconsistency detected. Computed number of GD entries doesn't match
3064 * stored value. Better be safe than sorry. */
3065 rc = VERR_VD_VMDK_INVALID_HEADER;
3066 goto out;
3067 }
3068 pExtent->uFreeSector = RT_LE2H_U32(Header.freeSector);
3069 pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
3070
3071 rc = vmdkReadGrainDirectory(pImage, pExtent);
3072
3073out:
3074 if (RT_FAILURE(rc))
3075 vmdkFreeExtentData(pImage, pExtent, false);
3076
3077 return rc;
3078}
3079#endif /* VBOX_WITH_VMDK_ESX */
3080
3081/**
3082 * Internal: free the buffers used for streamOptimized images.
3083 */
3084static void vmdkFreeStreamBuffers(PVMDKEXTENT pExtent)
3085{
3086 if (pExtent->pvCompGrain)
3087 {
3088 RTMemFree(pExtent->pvCompGrain);
3089 pExtent->pvCompGrain = NULL;
3090 }
3091 if (pExtent->pvGrain)
3092 {
3093 RTMemFree(pExtent->pvGrain);
3094 pExtent->pvGrain = NULL;
3095 }
3096}
3097
3098/**
3099 * Internal: free the memory used by the extent data structure, optionally
3100 * deleting the referenced files.
3101 */
3102static void vmdkFreeExtentData(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
3103 bool fDelete)
3104{
3105 vmdkFreeGrainDirectory(pExtent);
3106 if (pExtent->pDescData)
3107 {
3108 RTMemFree(pExtent->pDescData);
3109 pExtent->pDescData = NULL;
3110 }
3111 if (pExtent->pFile != NULL)
3112 {
3113 /* Do not delete raw extents, these have full and base names equal. */
3114 vmdkFileClose(pImage, &pExtent->pFile,
3115 fDelete
3116 && pExtent->pszFullname
3117 && strcmp(pExtent->pszFullname, pExtent->pszBasename));
3118 }
3119 if (pExtent->pszBasename)
3120 {
3121 RTMemTmpFree((void *)pExtent->pszBasename);
3122 pExtent->pszBasename = NULL;
3123 }
3124 if (pExtent->pszFullname)
3125 {
3126 RTStrFree((char *)(void *)pExtent->pszFullname);
3127 pExtent->pszFullname = NULL;
3128 }
3129 vmdkFreeStreamBuffers(pExtent);
3130}
3131
3132/**
3133 * Internal: allocate grain table cache if necessary for this image.
3134 */
3135static int vmdkAllocateGrainTableCache(PVMDKIMAGE pImage)
3136{
3137 PVMDKEXTENT pExtent;
3138
3139 /* Allocate grain table cache if any sparse extent is present. */
3140 for (unsigned i = 0; i < pImage->cExtents; i++)
3141 {
3142 pExtent = &pImage->pExtents[i];
3143 if ( pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
3144#ifdef VBOX_WITH_VMDK_ESX
3145 || pExtent->enmType == VMDKETYPE_ESX_SPARSE
3146#endif /* VBOX_WITH_VMDK_ESX */
3147 )
3148 {
3149 /* Allocate grain table cache. */
3150 pImage->pGTCache = (PVMDKGTCACHE)RTMemAllocZ(sizeof(VMDKGTCACHE));
3151 if (!pImage->pGTCache)
3152 return VERR_NO_MEMORY;
3153 for (unsigned j = 0; j < VMDK_GT_CACHE_SIZE; j++)
3154 {
3155 PVMDKGTCACHEENTRY pGCE = &pImage->pGTCache->aGTCache[j];
3156 pGCE->uExtent = UINT32_MAX;
3157 }
3158 pImage->pGTCache->cEntries = VMDK_GT_CACHE_SIZE;
3159 break;
3160 }
3161 }
3162
3163 return VINF_SUCCESS;
3164}
3165
3166/**
3167 * Internal: allocate the given number of extents.
3168 */
3169static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents)
3170{
3171 int rc = VINF_SUCCESS;
3172 PVMDKEXTENT pExtents = (PVMDKEXTENT)RTMemAllocZ(cExtents * sizeof(VMDKEXTENT));
3173 if (pExtents)
3174 {
3175 for (unsigned i = 0; i < cExtents; i++)
3176 {
3177 pExtents[i].pFile = NULL;
3178 pExtents[i].pszBasename = NULL;
3179 pExtents[i].pszFullname = NULL;
3180 pExtents[i].pGD = NULL;
3181 pExtents[i].pRGD = NULL;
3182 pExtents[i].pDescData = NULL;
3183 pExtents[i].uVersion = 1;
3184 pExtents[i].uCompression = VMDK_COMPRESSION_NONE;
3185 pExtents[i].uExtent = i;
3186 pExtents[i].pImage = pImage;
3187 }
3188 pImage->pExtents = pExtents;
3189 pImage->cExtents = cExtents;
3190 }
3191 else
3192 rc = VERR_NO_MEMORY;
3193
3194 return rc;
3195}
3196
3197/**
3198 * Internal: Open an image, constructing all necessary data structures.
3199 */
3200static int vmdkOpenImage(PVMDKIMAGE pImage, unsigned uOpenFlags)
3201{
3202 int rc;
3203 uint32_t u32Magic;
3204 PVMDKFILE pFile;
3205 PVMDKEXTENT pExtent;
3206
3207 pImage->uOpenFlags = uOpenFlags;
3208
3209 /* Try to get error interface. */
3210 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
3211 if (pImage->pInterfaceError)
3212 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
3213
3214 /* Get I/O interface. */
3215 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
3216 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
3217 pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
3218 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
3219
3220 /*
3221 * Open the image.
3222 * We don't have to check for asynchronous access because
3223 * we only support raw access and the opened file is a description
3224 * file were no data is stored.
3225 */
3226
3227 rc = vmdkFileOpen(pImage, &pFile, pImage->pszFilename,
3228 VDOpenFlagsToFileOpenFlags(uOpenFlags, false /* fCreate */),
3229 false /* fAsyncIO */);
3230 if (RT_FAILURE(rc))
3231 {
3232 /* Do NOT signal an appropriate error here, as the VD layer has the
3233 * choice of retrying the open if it failed. */
3234 goto out;
3235 }
3236 pImage->pFile = pFile;
3237
3238 /* Read magic (if present). */
3239 rc = vmdkFileReadSync(pImage, pFile, 0, &u32Magic, sizeof(u32Magic), NULL);
3240 if (RT_FAILURE(rc))
3241 {
3242 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error reading the magic number in '%s'"), pImage->pszFilename);
3243 goto out;
3244 }
3245
3246 /* Handle the file according to its magic number. */
3247 if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER)
3248 {
3249 /* It's a hosted single-extent image. */
3250 rc = vmdkCreateExtents(pImage, 1);
3251 if (RT_FAILURE(rc))
3252 goto out;
3253 /* The opened file is passed to the extent. No separate descriptor
3254 * file, so no need to keep anything open for the image. */
3255 pExtent = &pImage->pExtents[0];
3256 pExtent->pFile = pFile;
3257 pImage->pFile = NULL;
3258 pExtent->pszFullname = RTPathAbsDup(pImage->pszFilename);
3259 if (!pExtent->pszFullname)
3260 {
3261 rc = VERR_NO_MEMORY;
3262 goto out;
3263 }
3264 rc = vmdkReadBinaryMetaExtent(pImage, pExtent, true /* fMagicAlreadyRead */);
3265 if (RT_FAILURE(rc))
3266 goto out;
3267
3268 /* As we're dealing with a monolithic image here, there must
3269 * be a descriptor embedded in the image file. */
3270 if (!pExtent->uDescriptorSector || !pExtent->cDescriptorSectors)
3271 {
3272 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: monolithic image without descriptor in '%s'"), pImage->pszFilename);
3273 goto out;
3274 }
3275 /* HACK: extend the descriptor if it is unusually small and it fits in
3276 * the unused space after the image header. Allows opening VMDK files
3277 * with extremely small descriptor in read/write mode. */
3278 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
3279 && pExtent->cDescriptorSectors < 3
3280 && (int64_t)pExtent->uSectorGD - pExtent->uDescriptorSector >= 4
3281 && (!pExtent->uSectorRGD || (int64_t)pExtent->uSectorRGD - pExtent->uDescriptorSector >= 4))
3282 {
3283 pExtent->cDescriptorSectors = 4;
3284 pExtent->fMetaDirty = true;
3285 }
3286 /* Read the descriptor from the extent. */
3287 pExtent->pDescData = (char *)RTMemAllocZ(VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
3288 if (!pExtent->pDescData)
3289 {
3290 rc = VERR_NO_MEMORY;
3291 goto out;
3292 }
3293 rc = vmdkFileReadSync(pImage, pExtent->pFile,
3294 VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
3295 pExtent->pDescData,
3296 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);
3297 AssertRC(rc);
3298 if (RT_FAILURE(rc))
3299 {
3300 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pExtent->pszFullname);
3301 goto out;
3302 }
3303
3304 rc = vmdkParseDescriptor(pImage, pExtent->pDescData,
3305 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors));
3306 if (RT_FAILURE(rc))
3307 goto out;
3308
3309 rc = vmdkReadMetaExtent(pImage, pExtent);
3310 if (RT_FAILURE(rc))
3311 goto out;
3312
3313 /* Mark the extent as unclean if opened in read-write mode. */
3314 if ( !(uOpenFlags & VD_OPEN_FLAGS_READONLY)
3315 && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
3316 {
3317 pExtent->fUncleanShutdown = true;
3318 pExtent->fMetaDirty = true;
3319 }
3320 }
3321 else
3322 {
3323 /* Allocate at least 10K, and make sure that there is 5K free space
3324 * in case new entries need to be added to the descriptor. Never
3325 * allocate more than 128K, because that's no valid descriptor file
3326 * and will result in the correct "truncated read" error handling. */
3327 uint64_t cbFileSize;
3328 rc = vmdkFileGetSize(pImage, pFile, &cbFileSize);
3329 if (RT_FAILURE(rc))
3330 goto out;
3331
3332 /* If the descriptor file is shorter than 50 bytes it can't be valid. */
3333 if (cbFileSize < 50)
3334 {
3335 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor in '%s' is too short"), pImage->pszFilename);
3336 goto out;
3337 }
3338
3339 uint64_t cbSize = cbFileSize;
3340 if (cbSize % VMDK_SECTOR2BYTE(10))
3341 cbSize += VMDK_SECTOR2BYTE(20) - cbSize % VMDK_SECTOR2BYTE(10);
3342 else
3343 cbSize += VMDK_SECTOR2BYTE(10);
3344 cbSize = RT_MIN(cbSize, _128K);
3345 pImage->cbDescAlloc = RT_MAX(VMDK_SECTOR2BYTE(20), cbSize);
3346 pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
3347 if (!pImage->pDescData)
3348 {
3349 rc = VERR_NO_MEMORY;
3350 goto out;
3351 }
3352
3353 /* Don't reread the place where the magic would live in a sparse
3354 * image if it's a descriptor based one. */
3355 memcpy(pImage->pDescData, &u32Magic, sizeof(u32Magic));
3356 size_t cbRead;
3357 rc = vmdkFileReadSync(pImage, pImage->pFile, sizeof(u32Magic),
3358 pImage->pDescData + sizeof(u32Magic),
3359 RT_MIN(pImage->cbDescAlloc - sizeof(u32Magic),
3360 cbFileSize - sizeof(u32Magic)),
3361 &cbRead);
3362 if (RT_FAILURE(rc))
3363 {
3364 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: read error for descriptor in '%s'"), pImage->pszFilename);
3365 goto out;
3366 }
3367 cbRead += sizeof(u32Magic);
3368 if (cbRead == pImage->cbDescAlloc)
3369 {
3370 /* Likely the read is truncated. Better fail a bit too early
3371 * (normally the descriptor is much smaller than our buffer). */
3372 rc = vmdkError(pImage, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: cannot read descriptor in '%s'"), pImage->pszFilename);
3373 goto out;
3374 }
3375
3376 rc = vmdkParseDescriptor(pImage, pImage->pDescData,
3377 pImage->cbDescAlloc);
3378 if (RT_FAILURE(rc))
3379 goto out;
3380
3381 /*
3382 * We have to check for the asynchronous open flag. The
3383 * extents are parsed and the type of all are known now.
3384 * Check if every extent is either FLAT or ZERO.
3385 */
3386 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
3387 {
3388 unsigned cFlatExtents = 0;
3389
3390 for (unsigned i = 0; i < pImage->cExtents; i++)
3391 {
3392 pExtent = &pImage->pExtents[i];
3393
3394 if (( pExtent->enmType != VMDKETYPE_FLAT
3395 && pExtent->enmType != VMDKETYPE_ZERO
3396 && pExtent->enmType != VMDKETYPE_VMFS)
3397 || ((pImage->pExtents[i].enmType == VMDKETYPE_FLAT) && (cFlatExtents > 0)))
3398 {
3399 /*
3400 * Opened image contains at least one none flat or zero extent.
3401 * Return error but don't set error message as the caller
3402 * has the chance to open in non async I/O mode.
3403 */
3404 rc = VERR_NOT_SUPPORTED;
3405 goto out;
3406 }
3407 if (pExtent->enmType == VMDKETYPE_FLAT)
3408 cFlatExtents++;
3409 }
3410 }
3411
3412 for (unsigned i = 0; i < pImage->cExtents; i++)
3413 {
3414 pExtent = &pImage->pExtents[i];
3415
3416 if (pExtent->pszBasename)
3417 {
3418 /* Hack to figure out whether the specified name in the
3419 * extent descriptor is absolute. Doesn't always work, but
3420 * should be good enough for now. */
3421 char *pszFullname;
3422 /** @todo implement proper path absolute check. */
3423 if (pExtent->pszBasename[0] == RTPATH_SLASH)
3424 {
3425 pszFullname = RTStrDup(pExtent->pszBasename);
3426 if (!pszFullname)
3427 {
3428 rc = VERR_NO_MEMORY;
3429 goto out;
3430 }
3431 }
3432 else
3433 {
3434 char *pszDirname = RTStrDup(pImage->pszFilename);
3435 if (!pszDirname)
3436 {
3437 rc = VERR_NO_MEMORY;
3438 goto out;
3439 }
3440 RTPathStripFilename(pszDirname);
3441 pszFullname = RTPathJoinA(pszDirname, pExtent->pszBasename);
3442 RTStrFree(pszDirname);
3443 if (!pszFullname)
3444 {
3445 rc = VERR_NO_STR_MEMORY;
3446 goto out;
3447 }
3448 }
3449 pExtent->pszFullname = pszFullname;
3450 }
3451 else
3452 pExtent->pszFullname = NULL;
3453
3454 switch (pExtent->enmType)
3455 {
3456 case VMDKETYPE_HOSTED_SPARSE:
3457 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
3458 VDOpenFlagsToFileOpenFlags(uOpenFlags,
3459 false /* fCreate */),
3460 false /* fAsyncIO */);
3461 if (RT_FAILURE(rc))
3462 {
3463 /* Do NOT signal an appropriate error here, as the VD
3464 * layer has the choice of retrying the open if it
3465 * failed. */
3466 goto out;
3467 }
3468 rc = vmdkReadBinaryMetaExtent(pImage, pExtent,
3469 false /* fMagicAlreadyRead */);
3470 if (RT_FAILURE(rc))
3471 goto out;
3472 rc = vmdkReadMetaExtent(pImage, pExtent);
3473 if (RT_FAILURE(rc))
3474 goto out;
3475
3476 /* Mark extent as unclean if opened in read-write mode. */
3477 if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
3478 {
3479 pExtent->fUncleanShutdown = true;
3480 pExtent->fMetaDirty = true;
3481 }
3482 break;
3483 case VMDKETYPE_VMFS:
3484 case VMDKETYPE_FLAT:
3485 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
3486 VDOpenFlagsToFileOpenFlags(uOpenFlags,
3487 false /* fCreate */),
3488 true /* fAsyncIO */);
3489 if (RT_FAILURE(rc))
3490 {
3491 /* Do NOT signal an appropriate error here, as the VD
3492 * layer has the choice of retrying the open if it
3493 * failed. */
3494 goto out;
3495 }
3496 break;
3497 case VMDKETYPE_ZERO:
3498 /* Nothing to do. */
3499 break;
3500 default:
3501 AssertMsgFailed(("unknown vmdk extent type %d\n", pExtent->enmType));
3502 }
3503 }
3504 }
3505
3506 /* Make sure this is not reached accidentally with an error status. */
3507 AssertRC(rc);
3508
3509 /* Determine PCHS geometry if not set. */
3510 if (pImage->PCHSGeometry.cCylinders == 0)
3511 {
3512 uint64_t cCylinders = VMDK_BYTE2SECTOR(pImage->cbSize)
3513 / pImage->PCHSGeometry.cHeads
3514 / pImage->PCHSGeometry.cSectors;
3515 pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383);
3516 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
3517 && !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
3518 {
3519 rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry);
3520 AssertRC(rc);
3521 }
3522 }
3523
3524 /* Update the image metadata now in case has changed. */
3525 rc = vmdkFlushImage(pImage);
3526 if (RT_FAILURE(rc))
3527 goto out;
3528
3529 /* Figure out a few per-image constants from the extents. */
3530 pImage->cbSize = 0;
3531 for (unsigned i = 0; i < pImage->cExtents; i++)
3532 {
3533 pExtent = &pImage->pExtents[i];
3534 if ( pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
3535#ifdef VBOX_WITH_VMDK_ESX
3536 || pExtent->enmType == VMDKETYPE_ESX_SPARSE
3537#endif /* VBOX_WITH_VMDK_ESX */
3538 )
3539 {
3540 /* Here used to be a check whether the nominal size of an extent
3541 * is a multiple of the grain size. The spec says that this is
3542 * always the case, but unfortunately some files out there in the
3543 * wild violate the spec (e.g. ReactOS 0.3.1). */
3544 }
3545 pImage->cbSize += VMDK_SECTOR2BYTE(pExtent->cNominalSectors);
3546 }
3547
3548 for (unsigned i = 0; i < pImage->cExtents; i++)
3549 {
3550 pExtent = &pImage->pExtents[i];
3551 if ( pImage->pExtents[i].enmType == VMDKETYPE_FLAT
3552 || pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
3553 {
3554 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
3555 break;
3556 }
3557 }
3558
3559 if ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
3560 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
3561 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
3562 rc = vmdkAllocateGrainTableCache(pImage);
3563
3564out:
3565 if (RT_FAILURE(rc))
3566 vmdkFreeImage(pImage, false);
3567 return rc;
3568}
3569
3570/**
3571 * Internal: create VMDK images for raw disk/partition access.
3572 */
3573static int vmdkCreateRawImage(PVMDKIMAGE pImage, const PVBOXHDDRAW pRaw,
3574 uint64_t cbSize)
3575{
3576 int rc = VINF_SUCCESS;
3577 PVMDKEXTENT pExtent;
3578
3579 if (pRaw->fRawDisk)
3580 {
3581 /* Full raw disk access. This requires setting up a descriptor
3582 * file and open the (flat) raw disk. */
3583 rc = vmdkCreateExtents(pImage, 1);
3584 if (RT_FAILURE(rc))
3585 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
3586 pExtent = &pImage->pExtents[0];
3587 /* Create raw disk descriptor file. */
3588 rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
3589 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
3590 true /* fCreate */),
3591 false /* fAsyncIO */);
3592 if (RT_FAILURE(rc))
3593 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
3594
3595 /* Set up basename for extent description. Cannot use StrDup. */
3596 size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
3597 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
3598 if (!pszBasename)
3599 return VERR_NO_MEMORY;
3600 memcpy(pszBasename, pRaw->pszRawDisk, cbBasename);
3601 pExtent->pszBasename = pszBasename;
3602 /* For raw disks the full name is identical to the base name. */
3603 pExtent->pszFullname = RTStrDup(pszBasename);
3604 if (!pExtent->pszFullname)
3605 return VERR_NO_MEMORY;
3606 pExtent->enmType = VMDKETYPE_FLAT;
3607 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
3608 pExtent->uSectorOffset = 0;
3609 pExtent->enmAccess = VMDKACCESS_READWRITE;
3610 pExtent->fMetaDirty = false;
3611
3612 /* Open flat image, the raw disk. */
3613 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
3614 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
3615 false /* fCreate */),
3616 false /* fAsyncIO */);
3617 if (RT_FAILURE(rc))
3618 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
3619 }
3620 else
3621 {
3622 /* Raw partition access. This requires setting up a descriptor
3623 * file, write the partition information to a flat extent and
3624 * open all the (flat) raw disk partitions. */
3625
3626 /* First pass over the partition data areas to determine how many
3627 * extents we need. One data area can require up to 2 extents, as
3628 * it might be necessary to skip over unpartitioned space. */
3629 unsigned cExtents = 0;
3630 uint64_t uStart = 0;
3631 for (unsigned i = 0; i < pRaw->cPartDescs; i++)
3632 {
3633 PVBOXHDDRAWPARTDESC pPart = &pRaw->pPartDescs[i];
3634 if (uStart > pPart->uStart)
3635 return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: incorrect partition data area ordering set up by the caller in '%s'"), pImage->pszFilename);
3636
3637 if (uStart < pPart->uStart)
3638 cExtents++;
3639 uStart = pPart->uStart + pPart->cbData;
3640 cExtents++;
3641 }
3642 /* Another extent for filling up the rest of the image. */
3643 if (uStart != cbSize)
3644 cExtents++;
3645
3646 rc = vmdkCreateExtents(pImage, cExtents);
3647 if (RT_FAILURE(rc))
3648 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
3649
3650 /* Create raw partition descriptor file. */
3651 rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
3652 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
3653 true /* fCreate */),
3654 false /* fAsyncIO */);
3655 if (RT_FAILURE(rc))
3656 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
3657
3658 /* Create base filename for the partition table extent. */
3659 /** @todo remove fixed buffer without creating memory leaks. */
3660 char pszPartition[1024];
3661 const char *pszBase = RTPathFilename(pImage->pszFilename);
3662 const char *pszExt = RTPathExt(pszBase);
3663 if (pszExt == NULL)
3664 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pImage->pszFilename);
3665 char *pszBaseBase = RTStrDup(pszBase);
3666 if (!pszBaseBase)
3667 return VERR_NO_MEMORY;
3668 RTPathStripExt(pszBaseBase);
3669 RTStrPrintf(pszPartition, sizeof(pszPartition), "%s-pt%s",
3670 pszBaseBase, pszExt);
3671 RTStrFree(pszBaseBase);
3672
3673 /* Second pass over the partitions, now define all extents. */
3674 uint64_t uPartOffset = 0;
3675 cExtents = 0;
3676 uStart = 0;
3677 for (unsigned i = 0; i < pRaw->cPartDescs; i++)
3678 {
3679 PVBOXHDDRAWPARTDESC pPart = &pRaw->pPartDescs[i];
3680 pExtent = &pImage->pExtents[cExtents++];
3681
3682 if (uStart < pPart->uStart)
3683 {
3684 pExtent->pszBasename = NULL;
3685 pExtent->pszFullname = NULL;
3686 pExtent->enmType = VMDKETYPE_ZERO;
3687 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uStart - uStart);
3688 pExtent->uSectorOffset = 0;
3689 pExtent->enmAccess = VMDKACCESS_READWRITE;
3690 pExtent->fMetaDirty = false;
3691 /* go to next extent */
3692 pExtent = &pImage->pExtents[cExtents++];
3693 }
3694 uStart = pPart->uStart + pPart->cbData;
3695
3696 if (pPart->pvPartitionData)
3697 {
3698 /* Set up basename for extent description. Can't use StrDup. */
3699 size_t cbBasename = strlen(pszPartition) + 1;
3700 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
3701 if (!pszBasename)
3702 return VERR_NO_MEMORY;
3703 memcpy(pszBasename, pszPartition, cbBasename);
3704 pExtent->pszBasename = pszBasename;
3705
3706 /* Set up full name for partition extent. */
3707 char *pszDirname = RTStrDup(pImage->pszFilename);
3708 if (!pszDirname)
3709 return VERR_NO_STR_MEMORY;
3710 RTPathStripFilename(pszDirname);
3711 char *pszFullname = RTPathJoinA(pszDirname, pExtent->pszBasename);
3712 RTStrFree(pszDirname);
3713 if (!pszDirname)
3714 return VERR_NO_STR_MEMORY;
3715 pExtent->pszFullname = pszFullname;
3716 pExtent->enmType = VMDKETYPE_FLAT;
3717 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbData);
3718 pExtent->uSectorOffset = uPartOffset;
3719 pExtent->enmAccess = VMDKACCESS_READWRITE;
3720 pExtent->fMetaDirty = false;
3721
3722 /* Create partition table flat image. */
3723 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
3724 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
3725 true /* fCreate */),
3726 false /* fAsyncIO */);
3727 if (RT_FAILURE(rc))
3728 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
3729 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
3730 VMDK_SECTOR2BYTE(uPartOffset),
3731 pPart->pvPartitionData,
3732 pPart->cbData, NULL);
3733 if (RT_FAILURE(rc))
3734 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
3735 uPartOffset += VMDK_BYTE2SECTOR(pPart->cbData);
3736 }
3737 else
3738 {
3739 if (pPart->pszRawDevice)
3740 {
3741 /* Set up basename for extent descr. Can't use StrDup. */
3742 size_t cbBasename = strlen(pPart->pszRawDevice) + 1;
3743 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
3744 if (!pszBasename)
3745 return VERR_NO_MEMORY;
3746 memcpy(pszBasename, pPart->pszRawDevice, cbBasename);
3747 pExtent->pszBasename = pszBasename;
3748 /* For raw disks full name is identical to base name. */
3749 pExtent->pszFullname = RTStrDup(pszBasename);
3750 if (!pExtent->pszFullname)
3751 return VERR_NO_MEMORY;
3752 pExtent->enmType = VMDKETYPE_FLAT;
3753 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbData);
3754 pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uStartOffset);
3755 pExtent->enmAccess = VMDKACCESS_READWRITE;
3756 pExtent->fMetaDirty = false;
3757
3758 /* Open flat image, the raw partition. */
3759 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
3760 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags & ~VD_OPEN_FLAGS_READONLY,
3761 false /* fCreate */),
3762 false /* fAsyncIO */);
3763 if (RT_FAILURE(rc))
3764 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
3765 }
3766 else
3767 {
3768 pExtent->pszBasename = NULL;
3769 pExtent->pszFullname = NULL;
3770 pExtent->enmType = VMDKETYPE_ZERO;
3771 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbData);
3772 pExtent->uSectorOffset = 0;
3773 pExtent->enmAccess = VMDKACCESS_READWRITE;
3774 pExtent->fMetaDirty = false;
3775 }
3776 }
3777 }
3778 /* Another extent for filling up the rest of the image. */
3779 if (uStart != cbSize)
3780 {
3781 pExtent = &pImage->pExtents[cExtents++];
3782 pExtent->pszBasename = NULL;
3783 pExtent->pszFullname = NULL;
3784 pExtent->enmType = VMDKETYPE_ZERO;
3785 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize - uStart);
3786 pExtent->uSectorOffset = 0;
3787 pExtent->enmAccess = VMDKACCESS_READWRITE;
3788 pExtent->fMetaDirty = false;
3789 }
3790 }
3791
3792 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
3793 pRaw->fRawDisk ?
3794 "fullDevice" : "partitionedDevice");
3795 if (RT_FAILURE(rc))
3796 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
3797 return rc;
3798}
3799
3800/**
3801 * Internal: create a regular (i.e. file-backed) VMDK image.
3802 */
3803static int vmdkCreateRegularImage(PVMDKIMAGE pImage, uint64_t cbSize,
3804 unsigned uImageFlags,
3805 PFNVDPROGRESS pfnProgress, void *pvUser,
3806 unsigned uPercentStart, unsigned uPercentSpan)
3807{
3808 int rc = VINF_SUCCESS;
3809 unsigned cExtents = 1;
3810 uint64_t cbOffset = 0;
3811 uint64_t cbRemaining = cbSize;
3812
3813 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
3814 {
3815 cExtents = cbSize / VMDK_2G_SPLIT_SIZE;
3816 /* Do proper extent computation: need one smaller extent if the total
3817 * size isn't evenly divisible by the split size. */
3818 if (cbSize % VMDK_2G_SPLIT_SIZE)
3819 cExtents++;
3820 }
3821 rc = vmdkCreateExtents(pImage, cExtents);
3822 if (RT_FAILURE(rc))
3823 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
3824
3825 /* Basename strings needed for constructing the extent names. */
3826 char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
3827 AssertPtr(pszBasenameSubstr);
3828 size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
3829
3830 /* Create separate descriptor file if necessary. */
3831 if (cExtents != 1 || (uImageFlags & VD_IMAGE_FLAGS_FIXED))
3832 {
3833 rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
3834 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
3835 true /* fCreate */),
3836 false /* fAsyncIO */);
3837 if (RT_FAILURE(rc))
3838 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename);
3839 }
3840 else
3841 pImage->pFile = NULL;
3842
3843 /* Set up all extents. */
3844 for (unsigned i = 0; i < cExtents; i++)
3845 {
3846 PVMDKEXTENT pExtent = &pImage->pExtents[i];
3847 uint64_t cbExtent = cbRemaining;
3848
3849 /* Set up fullname/basename for extent description. Cannot use StrDup
3850 * for basename, as it is not guaranteed that the memory can be freed
3851 * with RTMemTmpFree, which must be used as in other code paths
3852 * StrDup is not usable. */
3853 if (cExtents == 1 && !(uImageFlags & VD_IMAGE_FLAGS_FIXED))
3854 {
3855 char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
3856 if (!pszBasename)
3857 return VERR_NO_MEMORY;
3858 memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
3859 pExtent->pszBasename = pszBasename;
3860 }
3861 else
3862 {
3863 char *pszBasenameExt = RTPathExt(pszBasenameSubstr);
3864 char *pszBasenameBase = RTStrDup(pszBasenameSubstr);
3865 RTPathStripExt(pszBasenameBase);
3866 char *pszTmp;
3867 size_t cbTmp;
3868 if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
3869 {
3870 if (cExtents == 1)
3871 RTStrAPrintf(&pszTmp, "%s-flat%s", pszBasenameBase,
3872 pszBasenameExt);
3873 else
3874 RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase,
3875 i+1, pszBasenameExt);
3876 }
3877 else
3878 RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, i+1,
3879 pszBasenameExt);
3880 RTStrFree(pszBasenameBase);
3881 if (!pszTmp)
3882 return VERR_NO_STR_MEMORY;
3883 cbTmp = strlen(pszTmp) + 1;
3884 char *pszBasename = (char *)RTMemTmpAlloc(cbTmp);
3885 if (!pszBasename)
3886 return VERR_NO_MEMORY;
3887 memcpy(pszBasename, pszTmp, cbTmp);
3888 RTStrFree(pszTmp);
3889 pExtent->pszBasename = pszBasename;
3890 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
3891 cbExtent = RT_MIN(cbRemaining, VMDK_2G_SPLIT_SIZE);
3892 }
3893 char *pszBasedirectory = RTStrDup(pImage->pszFilename);
3894 if (!pszBasedirectory)
3895 return VERR_NO_STR_MEMORY;
3896 RTPathStripFilename(pszBasedirectory);
3897 char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename);
3898 RTStrFree(pszBasedirectory);
3899 if (!pszFullname)
3900 return VERR_NO_STR_MEMORY;
3901 pExtent->pszFullname = pszFullname;
3902
3903 /* Create file for extent. */
3904 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
3905 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
3906 true /* fCreate */),
3907 false /* fAsyncIO */);
3908 if (RT_FAILURE(rc))
3909 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
3910 if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
3911 {
3912 rc = vmdkFileSetSize(pImage, pExtent->pFile, cbExtent);
3913 if (RT_FAILURE(rc))
3914 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
3915
3916 /* Fill image with zeroes. We do this for every fixed-size image since on some systems
3917 * (for example Windows Vista), it takes ages to write a block near the end of a sparse
3918 * file and the guest could complain about an ATA timeout. */
3919
3920 /** @todo Starting with Linux 2.6.23, there is an fallocate() system call.
3921 * Currently supported file systems are ext4 and ocfs2. */
3922
3923 /* Allocate a temporary zero-filled buffer. Use a bigger block size to optimize writing */
3924 const size_t cbBuf = 128 * _1K;
3925 void *pvBuf = RTMemTmpAllocZ(cbBuf);
3926 if (!pvBuf)
3927 return VERR_NO_MEMORY;
3928
3929 uint64_t uOff = 0;
3930 /* Write data to all image blocks. */
3931 while (uOff < cbExtent)
3932 {
3933 unsigned cbChunk = (unsigned)RT_MIN(cbExtent, cbBuf);
3934
3935 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uOff, pvBuf, cbChunk, NULL);
3936 if (RT_FAILURE(rc))
3937 {
3938 RTMemFree(pvBuf);
3939 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: writing block failed for '%s'"), pImage->pszFilename);
3940 }
3941
3942 uOff += cbChunk;
3943
3944 if (pfnProgress)
3945 {
3946 rc = pfnProgress(pvUser,
3947 uPercentStart + uOff * uPercentSpan / cbExtent);
3948 if (RT_FAILURE(rc))
3949 {
3950 RTMemFree(pvBuf);
3951 return rc;
3952 }
3953 }
3954 }
3955 RTMemTmpFree(pvBuf);
3956 }
3957
3958 /* Place descriptor file information (where integrated). */
3959 if (cExtents == 1 && !(uImageFlags & VD_IMAGE_FLAGS_FIXED))
3960 {
3961 pExtent->uDescriptorSector = 1;
3962 pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
3963 /* The descriptor is part of the (only) extent. */
3964 pExtent->pDescData = pImage->pDescData;
3965 pImage->pDescData = NULL;
3966 }
3967
3968 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
3969 {
3970 uint64_t cSectorsPerGDE, cSectorsPerGD;
3971 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
3972 pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbExtent, _64K));
3973 pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K);
3974 pExtent->cGTEntries = 512;
3975 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
3976 pExtent->cSectorsPerGDE = cSectorsPerGDE;
3977 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
3978 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
3979 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
3980 {
3981 /* The spec says version is 1 for all VMDKs, but the vast
3982 * majority of streamOptimized VMDKs actually contain
3983 * version 3 - so go with the majority. Both are accepted. */
3984 pExtent->uVersion = 3;
3985 pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
3986 }
3987 }
3988 else
3989 {
3990 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
3991 pExtent->enmType = VMDKETYPE_VMFS;
3992 else
3993 pExtent->enmType = VMDKETYPE_FLAT;
3994 }
3995
3996 pExtent->enmAccess = VMDKACCESS_READWRITE;
3997 pExtent->fUncleanShutdown = true;
3998 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbExtent);
3999 pExtent->uSectorOffset = 0;
4000 pExtent->fMetaDirty = true;
4001
4002 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
4003 {
4004 /* fPreAlloc should never be false because VMware can't use such images. */
4005 rc = vmdkCreateGrainDirectory(pImage, pExtent,
4006 RT_MAX( pExtent->uDescriptorSector
4007 + pExtent->cDescriptorSectors,
4008 1),
4009 true /* fPreAlloc */);
4010 if (RT_FAILURE(rc))
4011 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
4012 }
4013
4014 if (RT_SUCCESS(rc) && pfnProgress)
4015 pfnProgress(pvUser, uPercentStart + i * uPercentSpan / cExtents);
4016
4017 cbRemaining -= cbExtent;
4018 cbOffset += cbExtent;
4019 }
4020
4021 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
4022 {
4023 /* VirtualBox doesn't care, but VMWare ESX freaks out if the wrong
4024 * controller type is set in an image. */
4025 rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor, "ddb.adapterType", "lsilogic");
4026 if (RT_FAILURE(rc))
4027 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set controller type to lsilogic in '%s'"), pImage->pszFilename);
4028 }
4029
4030 const char *pszDescType = NULL;
4031 if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
4032 {
4033 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
4034 pszDescType = "vmfs";
4035 else
4036 pszDescType = (cExtents == 1)
4037 ? "monolithicFlat" : "twoGbMaxExtentFlat";
4038 }
4039 else
4040 {
4041 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4042 pszDescType = "streamOptimized";
4043 else
4044 {
4045 pszDescType = (cExtents == 1)
4046 ? "monolithicSparse" : "twoGbMaxExtentSparse";
4047 }
4048 }
4049 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
4050 pszDescType);
4051 if (RT_FAILURE(rc))
4052 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
4053 return rc;
4054}
4055
4056/**
4057 * Internal: Create a real stream optimized VMDK using only linear writes.
4058 */
4059static int vmdkCreateStreamImage(PVMDKIMAGE pImage, uint64_t cbSize,
4060 unsigned uImageFlags,
4061 PFNVDPROGRESS pfnProgress, void *pvUser,
4062 unsigned uPercentStart, unsigned uPercentSpan)
4063{
4064 int rc;
4065
4066 rc = vmdkCreateExtents(pImage, 1);
4067 if (RT_FAILURE(rc))
4068 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
4069
4070 /* Basename strings needed for constructing the extent names. */
4071 const char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
4072 AssertPtr(pszBasenameSubstr);
4073 size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
4074
4075 /* No separate descriptor file. */
4076 pImage->pFile = NULL;
4077
4078 /* Set up all extents. */
4079 PVMDKEXTENT pExtent = &pImage->pExtents[0];
4080
4081 /* Set up fullname/basename for extent description. Cannot use StrDup
4082 * for basename, as it is not guaranteed that the memory can be freed
4083 * with RTMemTmpFree, which must be used as in other code paths
4084 * StrDup is not usable. */
4085 char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
4086 if (!pszBasename)
4087 return VERR_NO_MEMORY;
4088 memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
4089 pExtent->pszBasename = pszBasename;
4090
4091 char *pszBasedirectory = RTStrDup(pImage->pszFilename);
4092 RTPathStripFilename(pszBasedirectory);
4093 char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename);
4094 RTStrFree(pszBasedirectory);
4095 if (!pszFullname)
4096 return VERR_NO_STR_MEMORY;
4097 pExtent->pszFullname = pszFullname;
4098
4099 /* Create file for extent. Make it write only, no reading allowed. */
4100 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
4101 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
4102 true /* fCreate */)
4103 & ~RTFILE_O_READ,
4104 false /* fAsyncIO */);
4105 if (RT_FAILURE(rc))
4106 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
4107
4108 /* Place descriptor file information. */
4109 pExtent->uDescriptorSector = 1;
4110 pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
4111 /* The descriptor is part of the (only) extent. */
4112 pExtent->pDescData = pImage->pDescData;
4113 pImage->pDescData = NULL;
4114
4115 uint64_t cSectorsPerGDE, cSectorsPerGD;
4116 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
4117 pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, _64K));
4118 pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K);
4119 pExtent->cGTEntries = 512;
4120 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
4121 pExtent->cSectorsPerGDE = cSectorsPerGDE;
4122 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
4123 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
4124
4125 /* The spec says version is 1 for all VMDKs, but the vast
4126 * majority of streamOptimized VMDKs actually contain
4127 * version 3 - so go with the majority. Both are accepted. */
4128 pExtent->uVersion = 3;
4129 pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
4130 pExtent->fFooter = true;
4131
4132 pExtent->enmAccess = VMDKACCESS_READONLY;
4133 pExtent->fUncleanShutdown = false;
4134 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
4135 pExtent->uSectorOffset = 0;
4136 pExtent->fMetaDirty = true;
4137
4138 /* Create grain directory, without preallocating it straight away. It will
4139 * be constructed on the fly when writing out the data and written when
4140 * closing the image. The end effect is that the full grain directory is
4141 * allocated, which is a requirement of the VMDK specs. */
4142 rc = vmdkCreateGrainDirectory(pImage, pExtent, VMDK_GD_AT_END,
4143 false /* fPreAlloc */);
4144 if (RT_FAILURE(rc))
4145 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
4146
4147 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
4148 "streamOptimized");
4149 if (RT_FAILURE(rc))
4150 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
4151
4152 return rc;
4153}
4154
4155/**
4156 * Internal: The actual code for creating any VMDK variant currently in
4157 * existence on hosted environments.
4158 */
4159static int vmdkCreateImage(PVMDKIMAGE pImage, uint64_t cbSize,
4160 unsigned uImageFlags, const char *pszComment,
4161 PCVDGEOMETRY pPCHSGeometry,
4162 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
4163 PFNVDPROGRESS pfnProgress, void *pvUser,
4164 unsigned uPercentStart, unsigned uPercentSpan)
4165{
4166 int rc;
4167
4168 pImage->uImageFlags = uImageFlags;
4169
4170 /* Try to get error interface. */
4171 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
4172 if (pImage->pInterfaceError)
4173 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
4174
4175 /* Get I/O interface. */
4176 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
4177 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
4178 pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
4179 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
4180
4181 rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
4182 &pImage->Descriptor);
4183 if (RT_FAILURE(rc))
4184 {
4185 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
4186 goto out;
4187 }
4188
4189 if ( (uImageFlags & VD_IMAGE_FLAGS_FIXED)
4190 && (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
4191 {
4192 /* Raw disk image (includes raw partition). */
4193 const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment;
4194 /* As the comment is misused, zap it so that no garbage comment
4195 * is set below. */
4196 pszComment = NULL;
4197 rc = vmdkCreateRawImage(pImage, pRaw, cbSize);
4198 }
4199 else
4200 {
4201 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4202 {
4203 /* Stream optimized sparse image (monolithic). */
4204 rc = vmdkCreateStreamImage(pImage, cbSize, uImageFlags,
4205 pfnProgress, pvUser, uPercentStart,
4206 uPercentSpan * 95 / 100);
4207 }
4208 else
4209 {
4210 /* Regular fixed or sparse image (monolithic or split). */
4211 rc = vmdkCreateRegularImage(pImage, cbSize, uImageFlags,
4212 pfnProgress, pvUser, uPercentStart,
4213 uPercentSpan * 95 / 100);
4214 }
4215 }
4216
4217 if (RT_FAILURE(rc))
4218 goto out;
4219
4220 if (RT_SUCCESS(rc) && pfnProgress)
4221 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
4222
4223 pImage->cbSize = cbSize;
4224
4225 for (unsigned i = 0; i < pImage->cExtents; i++)
4226 {
4227 PVMDKEXTENT pExtent = &pImage->pExtents[i];
4228
4229 rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
4230 pExtent->cNominalSectors, pExtent->enmType,
4231 pExtent->pszBasename, pExtent->uSectorOffset);
4232 if (RT_FAILURE(rc))
4233 {
4234 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
4235 goto out;
4236 }
4237 }
4238 vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
4239
4240 if ( pPCHSGeometry->cCylinders != 0
4241 && pPCHSGeometry->cHeads != 0
4242 && pPCHSGeometry->cSectors != 0)
4243 {
4244 rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
4245 if (RT_FAILURE(rc))
4246 goto out;
4247 }
4248 if ( pLCHSGeometry->cCylinders != 0
4249 && pLCHSGeometry->cHeads != 0
4250 && pLCHSGeometry->cSectors != 0)
4251 {
4252 rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
4253 if (RT_FAILURE(rc))
4254 goto out;
4255 }
4256
4257 pImage->LCHSGeometry = *pLCHSGeometry;
4258 pImage->PCHSGeometry = *pPCHSGeometry;
4259
4260 pImage->ImageUuid = *pUuid;
4261 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4262 VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
4263 if (RT_FAILURE(rc))
4264 {
4265 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
4266 goto out;
4267 }
4268 RTUuidClear(&pImage->ParentUuid);
4269 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4270 VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
4271 if (RT_FAILURE(rc))
4272 {
4273 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pImage->pszFilename);
4274 goto out;
4275 }
4276 RTUuidClear(&pImage->ModificationUuid);
4277 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4278 VMDK_DDB_MODIFICATION_UUID,
4279 &pImage->ModificationUuid);
4280 if (RT_FAILURE(rc))
4281 {
4282 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pImage->pszFilename);
4283 goto out;
4284 }
4285 RTUuidClear(&pImage->ParentModificationUuid);
4286 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4287 VMDK_DDB_PARENT_MODIFICATION_UUID,
4288 &pImage->ParentModificationUuid);
4289 if (RT_FAILURE(rc))
4290 {
4291 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in new descriptor in '%s'"), pImage->pszFilename);
4292 goto out;
4293 }
4294
4295 rc = vmdkAllocateGrainTableCache(pImage);
4296 if (RT_FAILURE(rc))
4297 goto out;
4298
4299 rc = vmdkSetImageComment(pImage, pszComment);
4300 if (RT_FAILURE(rc))
4301 {
4302 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
4303 goto out;
4304 }
4305
4306 if (RT_SUCCESS(rc) && pfnProgress)
4307 pfnProgress(pvUser, uPercentStart + uPercentSpan * 99 / 100);
4308
4309 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4310 {
4311 /* streamOptimized is a bit special, we cannot trigger the flush
4312 * until all data has been written. So we write the necessary
4313 * information explicitly. */
4314 pImage->pExtents[0].cDescriptorSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64( pImage->Descriptor.aLines[pImage->Descriptor.cLines]
4315 - pImage->Descriptor.aLines[0], 512));
4316 rc = vmdkWriteMetaSparseExtent(pImage, &pImage->pExtents[0], 0);
4317 if (RT_FAILURE(rc))
4318 {
4319 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK header in '%s'"), pImage->pszFilename);
4320 goto out;
4321 }
4322
4323 rc = vmdkWriteDescriptor(pImage);
4324 if (RT_FAILURE(rc))
4325 {
4326 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK descriptor in '%s'"), pImage->pszFilename);
4327 goto out;
4328 }
4329 }
4330 else
4331 rc = vmdkFlushImage(pImage);
4332
4333out:
4334 if (RT_SUCCESS(rc) && pfnProgress)
4335 pfnProgress(pvUser, uPercentStart + uPercentSpan);
4336
4337 if (RT_FAILURE(rc))
4338 vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
4339 return rc;
4340}
4341
4342/**
4343 * Internal: Update image comment.
4344 */
4345static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment)
4346{
4347 char *pszCommentEncoded;
4348 if (pszComment)
4349 {
4350 pszCommentEncoded = vmdkEncodeString(pszComment);
4351 if (!pszCommentEncoded)
4352 return VERR_NO_MEMORY;
4353 }
4354 else
4355 pszCommentEncoded = NULL;
4356 int rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor,
4357 "ddb.comment", pszCommentEncoded);
4358 if (pszComment)
4359 RTStrFree(pszCommentEncoded);
4360 if (RT_FAILURE(rc))
4361 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image comment in descriptor in '%s'"), pImage->pszFilename);
4362 return VINF_SUCCESS;
4363}
4364
4365/**
4366 * Internal. Clear the grain table buffer for real stream optimized writing.
4367 */
4368static void vmdkStreamClearGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
4369{
4370 uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
4371 for (uint32_t i = 0; i < cCacheLines; i++)
4372 memset(&pImage->pGTCache->aGTCache[i].aGTData[0], '\0',
4373 VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t));
4374}
4375
4376/**
4377 * Internal. Flush the grain table buffer for real stream optimized writing.
4378 */
4379static int vmdkStreamFlushGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4380 uint32_t uGDEntry)
4381{
4382 int rc = VINF_SUCCESS;
4383 uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
4384
4385 /* VMware does not write out completely empty grain tables in the case
4386 * of streamOptimized images, which according to my interpretation of
4387 * the VMDK 1.1 spec is bending the rules. Since they do it and we can
4388 * handle it without problems do it the same way and save some bytes. */
4389 bool fAllZero = true;
4390 for (uint32_t i = 0; i < cCacheLines; i++)
4391 {
4392 /* Convert the grain table to little endian in place, as it will not
4393 * be used at all after this function has been called. */
4394 uint32_t *pGTTmp = &pImage->pGTCache->aGTCache[i].aGTData[0];
4395 for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
4396 if (*pGTTmp)
4397 {
4398 fAllZero = false;
4399 break;
4400 }
4401 if (!fAllZero)
4402 break;
4403 }
4404 if (fAllZero)
4405 return VINF_SUCCESS;
4406
4407 uint64_t uFileOffset = pExtent->uAppendPosition;
4408 if (!uFileOffset)
4409 return VERR_INTERNAL_ERROR;
4410 /* Align to sector, as the previous write could have been any size. */
4411 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4412
4413 /* Grain table marker. */
4414 uint8_t aMarker[512];
4415 PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
4416 memset(pMarker, '\0', sizeof(aMarker));
4417 pMarker->uSector = RT_H2LE_U64(VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)));
4418 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GT);
4419 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
4420 aMarker, sizeof(aMarker), NULL);
4421 AssertRC(rc);
4422 uFileOffset += 512;
4423
4424 if (!pExtent->pGD || pExtent->pGD[uGDEntry])
4425 return VERR_INTERNAL_ERROR;
4426
4427 pExtent->pGD[uGDEntry] = VMDK_BYTE2SECTOR(uFileOffset);
4428
4429 for (uint32_t i = 0; i < cCacheLines; i++)
4430 {
4431 /* Convert the grain table to little endian in place, as it will not
4432 * be used at all after this function has been called. */
4433 uint32_t *pGTTmp = &pImage->pGTCache->aGTCache[i].aGTData[0];
4434 for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
4435 *pGTTmp = RT_H2LE_U32(*pGTTmp);
4436
4437 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
4438 &pImage->pGTCache->aGTCache[i].aGTData[0],
4439 VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t),
4440 NULL);
4441 uFileOffset += VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t);
4442 if (RT_FAILURE(rc))
4443 break;
4444 }
4445 Assert(!(uFileOffset % 512));
4446 pExtent->uAppendPosition = RT_ALIGN_64(uFileOffset, 512);
4447 return rc;
4448}
4449
4450/**
4451 * Internal. Free all allocated space for representing an image, and optionally
4452 * delete the image from disk.
4453 */
4454static int vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete)
4455{
4456 int rc = VINF_SUCCESS;
4457
4458 /* Freeing a never allocated image (e.g. because the open failed) is
4459 * not signalled as an error. After all nothing bad happens. */
4460 if (pImage)
4461 {
4462 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
4463 {
4464 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4465 {
4466 /* Check if all extents are clean. */
4467 for (unsigned i = 0; i < pImage->cExtents; i++)
4468 {
4469 Assert(!pImage->pExtents[i].fUncleanShutdown);
4470 }
4471 }
4472 else
4473 {
4474 /* Mark all extents as clean. */
4475 for (unsigned i = 0; i < pImage->cExtents; i++)
4476 {
4477 if ( ( pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
4478#ifdef VBOX_WITH_VMDK_ESX
4479 || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
4480#endif /* VBOX_WITH_VMDK_ESX */
4481 )
4482 && pImage->pExtents[i].fUncleanShutdown)
4483 {
4484 pImage->pExtents[i].fUncleanShutdown = false;
4485 pImage->pExtents[i].fMetaDirty = true;
4486 }
4487
4488 /* From now on it's not safe to append any more data. */
4489 pImage->pExtents[i].uAppendPosition = 0;
4490 }
4491 }
4492 }
4493
4494 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4495 {
4496 /* No need to write any pending data if the file will be deleted
4497 * or if the new file wasn't successfully created. */
4498 if ( !fDelete && pImage->pExtents
4499 && pImage->pExtents[0].cGTEntries
4500 && pImage->pExtents[0].uAppendPosition)
4501 {
4502 PVMDKEXTENT pExtent = &pImage->pExtents[0];
4503 uint32_t uLastGDEntry = pExtent->uLastGrainAccess / pExtent->cGTEntries;
4504 if (uLastGDEntry != pExtent->cGDEntries - 1)
4505 {
4506 rc = vmdkStreamFlushGT(pImage, pExtent, uLastGDEntry);
4507 AssertRC(rc);
4508 vmdkStreamClearGT(pImage, pExtent);
4509 for (uint32_t i = uLastGDEntry + 1; i < pExtent->cGDEntries; i++)
4510 {
4511 rc = vmdkStreamFlushGT(pImage, pExtent, i);
4512 AssertRC(rc);
4513 }
4514 }
4515
4516 uint64_t uFileOffset = pExtent->uAppendPosition;
4517 if (!uFileOffset)
4518 return VERR_INTERNAL_ERROR;
4519 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4520
4521 /* From now on it's not safe to append any more data. */
4522 pExtent->uAppendPosition = 0;
4523
4524 /* Grain directory marker. */
4525 uint8_t aMarker[512];
4526 PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
4527 memset(pMarker, '\0', sizeof(aMarker));
4528 pMarker->uSector = VMDK_BYTE2SECTOR(RT_ALIGN_64(RT_H2LE_U64(pExtent->cGDEntries * sizeof(uint32_t)), 512));
4529 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GD);
4530 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
4531 aMarker, sizeof(aMarker), NULL);
4532 AssertRC(rc);
4533 uFileOffset += 512;
4534
4535 /* Write grain directory in little endian style. The array will
4536 * not be used after this, so convert in place. */
4537 uint32_t *pGDTmp = pExtent->pGD;
4538 for (uint32_t i = 0; i < pExtent->cGDEntries; i++, pGDTmp++)
4539 *pGDTmp = RT_H2LE_U32(*pGDTmp);
4540 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
4541 pExtent->pGD,
4542 pExtent->cGDEntries * sizeof(uint32_t),
4543 NULL);
4544 AssertRC(rc);
4545
4546 pExtent->uSectorGD = VMDK_BYTE2SECTOR(uFileOffset);
4547 pExtent->uSectorRGD = VMDK_BYTE2SECTOR(uFileOffset);
4548 uFileOffset = RT_ALIGN_64( uFileOffset
4549 + pExtent->cGDEntries * sizeof(uint32_t),
4550 512);
4551
4552 /* Footer marker. */
4553 memset(pMarker, '\0', sizeof(aMarker));
4554 pMarker->uSector = VMDK_BYTE2SECTOR(512);
4555 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_FOOTER);
4556 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
4557 aMarker, sizeof(aMarker), NULL);
4558 AssertRC(rc);
4559
4560 uFileOffset += 512;
4561 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
4562 AssertRC(rc);
4563
4564 uFileOffset += 512;
4565 /* End-of-stream marker. */
4566 memset(pMarker, '\0', sizeof(aMarker));
4567 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
4568 aMarker, sizeof(aMarker), NULL);
4569 AssertRC(rc);
4570 }
4571 }
4572 else
4573 vmdkFlushImage(pImage);
4574
4575 if (pImage->pExtents != NULL)
4576 {
4577 for (unsigned i = 0 ; i < pImage->cExtents; i++)
4578 vmdkFreeExtentData(pImage, &pImage->pExtents[i], fDelete);
4579 RTMemFree(pImage->pExtents);
4580 pImage->pExtents = NULL;
4581 }
4582 pImage->cExtents = 0;
4583 if (pImage->pFile != NULL)
4584 vmdkFileClose(pImage, &pImage->pFile, fDelete);
4585 vmdkFileCheckAllClose(pImage);
4586
4587 if (pImage->pGTCache)
4588 {
4589 RTMemFree(pImage->pGTCache);
4590 pImage->pGTCache = NULL;
4591 }
4592 if (pImage->pDescData)
4593 {
4594 RTMemFree(pImage->pDescData);
4595 pImage->pDescData = NULL;
4596 }
4597 }
4598
4599 LogFlowFunc(("returns %Rrc\n", rc));
4600 return rc;
4601}
4602
4603/**
4604 * Internal. Flush image data (and metadata) to disk.
4605 */
4606static int vmdkFlushImage(PVMDKIMAGE pImage)
4607{
4608 PVMDKEXTENT pExtent;
4609 int rc = VINF_SUCCESS;
4610
4611 /* Update descriptor if changed. */
4612 if (pImage->Descriptor.fDirty)
4613 {
4614 rc = vmdkWriteDescriptor(pImage);
4615 if (RT_FAILURE(rc))
4616 goto out;
4617 }
4618
4619 for (unsigned i = 0; i < pImage->cExtents; i++)
4620 {
4621 pExtent = &pImage->pExtents[i];
4622 if (pExtent->pFile != NULL && pExtent->fMetaDirty)
4623 {
4624 switch (pExtent->enmType)
4625 {
4626 case VMDKETYPE_HOSTED_SPARSE:
4627 if (!pExtent->fFooter)
4628 {
4629 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, 0);
4630 if (RT_FAILURE(rc))
4631 goto out;
4632 }
4633 else
4634 {
4635 uint64_t uFileOffset = pExtent->uAppendPosition;
4636 /* Simply skip writing anything if the streamOptimized
4637 * image hasn't been just created. */
4638 if (!uFileOffset)
4639 break;
4640 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4641 rc = vmdkWriteMetaSparseExtent(pImage, pExtent,
4642 uFileOffset);
4643 if (RT_FAILURE(rc))
4644 goto out;
4645 }
4646 break;
4647#ifdef VBOX_WITH_VMDK_ESX
4648 case VMDKETYPE_ESX_SPARSE:
4649 /** @todo update the header. */
4650 break;
4651#endif /* VBOX_WITH_VMDK_ESX */
4652 case VMDKETYPE_VMFS:
4653 case VMDKETYPE_FLAT:
4654 /* Nothing to do. */
4655 break;
4656 case VMDKETYPE_ZERO:
4657 default:
4658 AssertMsgFailed(("extent with type %d marked as dirty\n",
4659 pExtent->enmType));
4660 break;
4661 }
4662 }
4663 switch (pExtent->enmType)
4664 {
4665 case VMDKETYPE_HOSTED_SPARSE:
4666#ifdef VBOX_WITH_VMDK_ESX
4667 case VMDKETYPE_ESX_SPARSE:
4668#endif /* VBOX_WITH_VMDK_ESX */
4669 case VMDKETYPE_VMFS:
4670 case VMDKETYPE_FLAT:
4671 /** @todo implement proper path absolute check. */
4672 if ( pExtent->pFile != NULL
4673 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
4674 && !(pExtent->pszBasename[0] == RTPATH_SLASH))
4675 rc = vmdkFileFlush(pImage, pExtent->pFile);
4676 break;
4677 case VMDKETYPE_ZERO:
4678 /* No need to do anything for this extent. */
4679 break;
4680 default:
4681 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
4682 break;
4683 }
4684 }
4685
4686out:
4687 return rc;
4688}
4689
4690/**
4691 * Internal. Flush image data (and metadata) to disk - async version.
4692 */
4693static int vmdkFlushImageAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
4694{
4695 PVMDKEXTENT pExtent;
4696 int rc = VINF_SUCCESS;
4697
4698 /* Update descriptor if changed. */
4699 if (pImage->Descriptor.fDirty)
4700 {
4701 rc = vmdkWriteDescriptorAsync(pImage, pIoCtx);
4702 if ( RT_FAILURE(rc)
4703 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
4704 goto out;
4705 }
4706
4707 for (unsigned i = 0; i < pImage->cExtents; i++)
4708 {
4709 pExtent = &pImage->pExtents[i];
4710 if (pExtent->pFile != NULL && pExtent->fMetaDirty)
4711 {
4712 switch (pExtent->enmType)
4713 {
4714 case VMDKETYPE_HOSTED_SPARSE:
4715 AssertMsgFailed(("Async I/O not supported for sparse images\n"));
4716 break;
4717#ifdef VBOX_WITH_VMDK_ESX
4718 case VMDKETYPE_ESX_SPARSE:
4719 /** @todo update the header. */
4720 break;
4721#endif /* VBOX_WITH_VMDK_ESX */
4722 case VMDKETYPE_VMFS:
4723 case VMDKETYPE_FLAT:
4724 /* Nothing to do. */
4725 break;
4726 case VMDKETYPE_ZERO:
4727 default:
4728 AssertMsgFailed(("extent with type %d marked as dirty\n",
4729 pExtent->enmType));
4730 break;
4731 }
4732 }
4733 switch (pExtent->enmType)
4734 {
4735 case VMDKETYPE_HOSTED_SPARSE:
4736#ifdef VBOX_WITH_VMDK_ESX
4737 case VMDKETYPE_ESX_SPARSE:
4738#endif /* VBOX_WITH_VMDK_ESX */
4739 case VMDKETYPE_VMFS:
4740 case VMDKETYPE_FLAT:
4741 /** @todo implement proper path absolute check. */
4742 if ( pExtent->pFile != NULL
4743 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
4744 && !(pExtent->pszBasename[0] == RTPATH_SLASH))
4745 rc = vmdkFileFlushAsync(pImage, pExtent->pFile, pIoCtx);
4746 break;
4747 case VMDKETYPE_ZERO:
4748 /* No need to do anything for this extent. */
4749 break;
4750 default:
4751 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
4752 break;
4753 }
4754 }
4755
4756out:
4757 return rc;
4758}
4759
4760/**
4761 * Internal. Find extent corresponding to the sector number in the disk.
4762 */
4763static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector,
4764 PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
4765{
4766 PVMDKEXTENT pExtent = NULL;
4767 int rc = VINF_SUCCESS;
4768
4769 for (unsigned i = 0; i < pImage->cExtents; i++)
4770 {
4771 if (offSector < pImage->pExtents[i].cNominalSectors)
4772 {
4773 pExtent = &pImage->pExtents[i];
4774 *puSectorInExtent = offSector + pImage->pExtents[i].uSectorOffset;
4775 break;
4776 }
4777 offSector -= pImage->pExtents[i].cNominalSectors;
4778 }
4779
4780 if (pExtent)
4781 *ppExtent = pExtent;
4782 else
4783 rc = VERR_IO_SECTOR_NOT_FOUND;
4784
4785 return rc;
4786}
4787
4788/**
4789 * Internal. Hash function for placing the grain table hash entries.
4790 */
4791static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector,
4792 unsigned uExtent)
4793{
4794 /** @todo this hash function is quite simple, maybe use a better one which
4795 * scrambles the bits better. */
4796 return (uSector + uExtent) % pCache->cEntries;
4797}
4798
4799/**
4800 * Internal. Get sector number in the extent file from the relative sector
4801 * number in the extent.
4802 */
4803static int vmdkGetSector(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4804 uint64_t uSector, uint64_t *puExtentSector)
4805{
4806 PVMDKGTCACHE pCache = pImage->pGTCache;
4807 uint64_t uGDIndex, uGTSector, uGTBlock;
4808 uint32_t uGTHash, uGTBlockIndex;
4809 PVMDKGTCACHEENTRY pGTCacheEntry;
4810 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
4811 int rc;
4812
4813 /* For newly created and readonly/sequentially opened streamOptimized
4814 * images this must be a no-op, as the grain directory is not there. */
4815 if ( ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
4816 && pExtent->uAppendPosition)
4817 || ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
4818 && pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY
4819 && pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
4820 {
4821 *puExtentSector = 0;
4822 return VINF_SUCCESS;
4823 }
4824
4825 uGDIndex = uSector / pExtent->cSectorsPerGDE;
4826 if (uGDIndex >= pExtent->cGDEntries)
4827 return VERR_OUT_OF_RANGE;
4828 uGTSector = pExtent->pGD[uGDIndex];
4829 if (!uGTSector)
4830 {
4831 /* There is no grain table referenced by this grain directory
4832 * entry. So there is absolutely no data in this area. */
4833 *puExtentSector = 0;
4834 return VINF_SUCCESS;
4835 }
4836
4837 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
4838 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
4839 pGTCacheEntry = &pCache->aGTCache[uGTHash];
4840 if ( pGTCacheEntry->uExtent != pExtent->uExtent
4841 || pGTCacheEntry->uGTBlock != uGTBlock)
4842 {
4843 /* Cache miss, fetch data from disk. */
4844 rc = vmdkFileReadSync(pImage, pExtent->pFile,
4845 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
4846 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4847 if (RT_FAILURE(rc))
4848 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
4849 pGTCacheEntry->uExtent = pExtent->uExtent;
4850 pGTCacheEntry->uGTBlock = uGTBlock;
4851 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
4852 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
4853 }
4854 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
4855 uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
4856 if (uGrainSector)
4857 *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
4858 else
4859 *puExtentSector = 0;
4860 return VINF_SUCCESS;
4861}
4862
4863/**
4864 * Internal. Get sector number in the extent file from the relative sector
4865 * number in the extent - version for async access.
4866 */
4867static int vmdkGetSectorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx,
4868 PVMDKEXTENT pExtent, uint64_t uSector,
4869 uint64_t *puExtentSector)
4870{
4871 PVMDKGTCACHE pCache = pImage->pGTCache;
4872 uint64_t uGDIndex, uGTSector, uGTBlock;
4873 uint32_t uGTHash, uGTBlockIndex;
4874 PVMDKGTCACHEENTRY pGTCacheEntry;
4875 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
4876 int rc;
4877
4878 uGDIndex = uSector / pExtent->cSectorsPerGDE;
4879 if (uGDIndex >= pExtent->cGDEntries)
4880 return VERR_OUT_OF_RANGE;
4881 uGTSector = pExtent->pGD[uGDIndex];
4882 if (!uGTSector)
4883 {
4884 /* There is no grain table referenced by this grain directory
4885 * entry. So there is absolutely no data in this area. */
4886 *puExtentSector = 0;
4887 return VINF_SUCCESS;
4888 }
4889
4890 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
4891 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
4892 pGTCacheEntry = &pCache->aGTCache[uGTHash];
4893 if ( pGTCacheEntry->uExtent != pExtent->uExtent
4894 || pGTCacheEntry->uGTBlock != uGTBlock)
4895 {
4896 /* Cache miss, fetch data from disk. */
4897 PVDMETAXFER pMetaXfer;
4898 rc = vmdkFileReadMetaAsync(pImage, pExtent->pFile,
4899 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
4900 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer, NULL, NULL);
4901 if (RT_FAILURE(rc))
4902 return rc;
4903 /* We can release the metadata transfer immediately. */
4904 vmdkFileMetaXferRelease(pImage, pMetaXfer);
4905 pGTCacheEntry->uExtent = pExtent->uExtent;
4906 pGTCacheEntry->uGTBlock = uGTBlock;
4907 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
4908 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
4909 }
4910 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
4911 uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
4912 if (uGrainSector)
4913 *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
4914 else
4915 *puExtentSector = 0;
4916 return VINF_SUCCESS;
4917}
4918
4919/**
4920 * Internal. Allocates a new grain table (if necessary), writes the grain
4921 * and updates the grain table. The cache is also updated by this operation.
4922 * This is separate from vmdkGetSector, because that should be as fast as
4923 * possible. Most code from vmdkGetSector also appears here.
4924 */
4925static int vmdkAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4926 uint64_t uSector, const void *pvBuf,
4927 uint64_t cbWrite)
4928{
4929 PVMDKGTCACHE pCache = pImage->pGTCache;
4930 uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
4931 uint64_t uFileOffset;
4932 uint32_t uGTHash, uGTBlockIndex;
4933 PVMDKGTCACHEENTRY pGTCacheEntry;
4934 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
4935 int rc;
4936
4937 uGDIndex = uSector / pExtent->cSectorsPerGDE;
4938 if (uGDIndex >= pExtent->cGDEntries)
4939 return VERR_OUT_OF_RANGE;
4940 uGTSector = pExtent->pGD[uGDIndex];
4941 if (pExtent->pRGD)
4942 uRGTSector = pExtent->pRGD[uGDIndex];
4943 else
4944 uRGTSector = 0; /**< avoid compiler warning */
4945 if (!uGTSector)
4946 {
4947 /* There is no grain table referenced by this grain directory
4948 * entry. So there is absolutely no data in this area. Allocate
4949 * a new grain table and put the reference to it in the GDs. */
4950 uFileOffset = pExtent->uAppendPosition;
4951 if (!uFileOffset)
4952 return VERR_INTERNAL_ERROR;
4953 Assert(!(uFileOffset % 512));
4954 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4955 uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
4956
4957 pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
4958
4959 /* Normally the grain table is preallocated for hosted sparse extents
4960 * that support more than 32 bit sector numbers. So this shouldn't
4961 * ever happen on a valid extent. */
4962 if (uGTSector > UINT32_MAX)
4963 return VERR_VD_VMDK_INVALID_HEADER;
4964
4965 /* Write grain table by writing the required number of grain table
4966 * cache chunks. Avoids dynamic memory allocation, but is a bit
4967 * slower. But as this is a pretty infrequently occurring case it
4968 * should be acceptable. */
4969 memset(aGTDataTmp, '\0', sizeof(aGTDataTmp));
4970 for (unsigned i = 0;
4971 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
4972 i++)
4973 {
4974 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
4975 VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
4976 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4977 if (RT_FAILURE(rc))
4978 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
4979 }
4980 pExtent->uAppendPosition = RT_ALIGN_64( pExtent->uAppendPosition
4981 + pExtent->cGTEntries * sizeof(uint32_t),
4982 512);
4983
4984 if (pExtent->pRGD)
4985 {
4986 AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
4987 uFileOffset = pExtent->uAppendPosition;
4988 if (!uFileOffset)
4989 return VERR_INTERNAL_ERROR;
4990 Assert(!(uFileOffset % 512));
4991 uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
4992
4993 pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
4994
4995 /* Normally the redundant grain table is preallocated for hosted
4996 * sparse extents that support more than 32 bit sector numbers. So
4997 * this shouldn't ever happen on a valid extent. */
4998 if (uRGTSector > UINT32_MAX)
4999 return VERR_VD_VMDK_INVALID_HEADER;
5000
5001 /* Write backup grain table by writing the required number of grain
5002 * table cache chunks. Avoids dynamic memory allocation, but is a
5003 * bit slower. But as this is a pretty infrequently occurring case
5004 * it should be acceptable. */
5005 for (unsigned i = 0;
5006 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
5007 i++)
5008 {
5009 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
5010 VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
5011 aGTDataTmp, sizeof(aGTDataTmp), NULL);
5012 if (RT_FAILURE(rc))
5013 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
5014 }
5015
5016 pExtent->uAppendPosition = pExtent->uAppendPosition
5017 + pExtent->cGTEntries * sizeof(uint32_t);
5018 }
5019
5020 /* Update the grain directory on disk (doing it before writing the
5021 * grain table will result in a garbled extent if the operation is
5022 * aborted for some reason. Otherwise the worst that can happen is
5023 * some unused sectors in the extent. */
5024 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
5025 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
5026 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
5027 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
5028 if (RT_FAILURE(rc))
5029 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
5030 if (pExtent->pRGD)
5031 {
5032 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
5033 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
5034 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
5035 &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
5036 if (RT_FAILURE(rc))
5037 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
5038 }
5039
5040 /* As the final step update the in-memory copy of the GDs. */
5041 pExtent->pGD[uGDIndex] = uGTSector;
5042 if (pExtent->pRGD)
5043 pExtent->pRGD[uGDIndex] = uRGTSector;
5044 }
5045
5046 uFileOffset = pExtent->uAppendPosition;
5047 if (!uFileOffset)
5048 return VERR_INTERNAL_ERROR;
5049 Assert(!(uFileOffset % 512));
5050
5051 /* Write the data. Always a full grain, or we're in big trouble. */
5052 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
5053 {
5054 if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
5055 return vmdkError(pImage, VERR_INTERNAL_ERROR, RT_SRC_POS, N_("VMDK: not enough data for a compressed data block in '%s'"), pExtent->pszFullname);
5056
5057 /* Invalidate cache, just in case some code incorrectly allows mixing
5058 * of reads and writes. Normally shouldn't be needed. */
5059 pExtent->uGrainSectorAbs = 0;
5060
5061 /* Write compressed data block and the markers. */
5062 uint32_t cbGrain = 0;
5063 rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset,
5064 pvBuf, cbWrite, uSector, &cbGrain);
5065 if (RT_FAILURE(rc))
5066 {
5067 AssertRC(rc);
5068 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated compressed data block in '%s'"), pExtent->pszFullname);
5069 }
5070 pExtent->uLastGrainAccess = uSector / pExtent->cSectorsPerGrain;
5071 pExtent->uAppendPosition += cbGrain;
5072 }
5073 else
5074 {
5075 rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
5076 pvBuf, cbWrite, NULL);
5077 if (RT_FAILURE(rc))
5078 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
5079 pExtent->uAppendPosition += cbWrite;
5080 }
5081
5082 /* Update the grain table (and the cache). */
5083 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
5084 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
5085 pGTCacheEntry = &pCache->aGTCache[uGTHash];
5086 if ( pGTCacheEntry->uExtent != pExtent->uExtent
5087 || pGTCacheEntry->uGTBlock != uGTBlock)
5088 {
5089 /* Cache miss, fetch data from disk. */
5090 rc = vmdkFileReadSync(pImage, pExtent->pFile,
5091 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5092 aGTDataTmp, sizeof(aGTDataTmp), NULL);
5093 if (RT_FAILURE(rc))
5094 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
5095 pGTCacheEntry->uExtent = pExtent->uExtent;
5096 pGTCacheEntry->uGTBlock = uGTBlock;
5097 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
5098 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
5099 }
5100 else
5101 {
5102 /* Cache hit. Convert grain table block back to disk format, otherwise
5103 * the code below will write garbage for all but the updated entry. */
5104 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
5105 aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
5106 }
5107 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
5108 aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(uFileOffset));
5109 pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(uFileOffset);
5110 /* Update grain table on disk. */
5111 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
5112 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5113 aGTDataTmp, sizeof(aGTDataTmp), NULL);
5114 if (RT_FAILURE(rc))
5115 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
5116 if (pExtent->pRGD)
5117 {
5118 /* Update backup grain table on disk. */
5119 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
5120 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5121 aGTDataTmp, sizeof(aGTDataTmp), NULL);
5122 if (RT_FAILURE(rc))
5123 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
5124 }
5125#ifdef VBOX_WITH_VMDK_ESX
5126 if (RT_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
5127 {
5128 pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
5129 pExtent->fMetaDirty = true;
5130 }
5131#endif /* VBOX_WITH_VMDK_ESX */
5132 return rc;
5133}
5134
5135/**
5136 * Internal. Writes the grain and also if necessary the grain tables.
5137 * Uses the grain table cache as a true grain table.
5138 */
5139static int vmdkStreamAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
5140 uint64_t uSector, const void *pvBuf,
5141 uint64_t cbWrite)
5142{
5143 uint32_t uGrain;
5144 uint32_t uGDEntry, uLastGDEntry;
5145 uint32_t cbGrain = 0;
5146 uint32_t uCacheLine, uCacheEntry;
5147 const void *pData = pvBuf;
5148 int rc;
5149
5150 /* Very strict requirements: always write at least one full grain, with
5151 * proper alignment. Everything else would require reading of already
5152 * written data, which we don't support for obvious reasons. The only
5153 * exception is the last grain, and only if the image size specifies
5154 * that only some portion holds data. In any case the write must be
5155 * within the image limits, no "overshoot" allowed. */
5156 if ( cbWrite == 0
5157 || ( cbWrite < VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
5158 && pExtent->cNominalSectors - uSector >= pExtent->cSectorsPerGrain)
5159 || uSector % pExtent->cSectorsPerGrain
5160 || uSector + VMDK_BYTE2SECTOR(cbWrite) > pExtent->cNominalSectors)
5161 return VERR_INVALID_PARAMETER;
5162
5163 /* Clip write range to at most the rest of the grain. */
5164 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSector % pExtent->cSectorsPerGrain));
5165
5166 /* Do not allow to go back. */
5167 uGrain = uSector / pExtent->cSectorsPerGrain;
5168 uCacheLine = uGrain % pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
5169 uCacheEntry = uGrain % VMDK_GT_CACHELINE_SIZE;
5170 uGDEntry = uGrain / pExtent->cGTEntries;
5171 uLastGDEntry = pExtent->uLastGrainAccess / pExtent->cGTEntries;
5172 if (uGrain < pExtent->uLastGrainAccess)
5173 return VERR_VD_VMDK_INVALID_WRITE;
5174
5175 /* Zero byte write optimization. Since we don't tell VBoxHDD that we need
5176 * to allocate something, we also need to detect the situation ourself. */
5177 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
5178 && ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbWrite * 8) == -1)
5179 return VINF_SUCCESS;
5180
5181 if (uGDEntry != uLastGDEntry)
5182 {
5183 rc = vmdkStreamFlushGT(pImage, pExtent, uLastGDEntry);
5184 if (RT_FAILURE(rc))
5185 return rc;
5186 vmdkStreamClearGT(pImage, pExtent);
5187 for (uint32_t i = uLastGDEntry + 1; i < uGDEntry; i++)
5188 {
5189 rc = vmdkStreamFlushGT(pImage, pExtent, i);
5190 if (RT_FAILURE(rc))
5191 return rc;
5192 }
5193 }
5194
5195 uint64_t uFileOffset;
5196 uFileOffset = pExtent->uAppendPosition;
5197 if (!uFileOffset)
5198 return VERR_INTERNAL_ERROR;
5199 /* Align to sector, as the previous write could have been any size. */
5200 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
5201
5202 /* Paranoia check: extent type, grain table buffer presence and
5203 * grain table buffer space. Also grain table entry must be clear. */
5204 if ( pExtent->enmType != VMDKETYPE_HOSTED_SPARSE
5205 || !pImage->pGTCache
5206 || pExtent->cGTEntries > VMDK_GT_CACHE_SIZE * VMDK_GT_CACHELINE_SIZE
5207 || pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry])
5208 return VERR_INTERNAL_ERROR;
5209
5210 /* Update grain table entry. */
5211 pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry] = VMDK_BYTE2SECTOR(uFileOffset);
5212
5213 if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
5214 {
5215 memcpy(pExtent->pvGrain, pvBuf, cbWrite);
5216 memset((char *)pExtent->pvGrain + cbWrite, '\0',
5217 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite);
5218 pData = pExtent->pvGrain;
5219 }
5220 rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset, pData,
5221 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
5222 uSector, &cbGrain);
5223 if (RT_FAILURE(rc))
5224 {
5225 pExtent->uGrainSectorAbs = 0;
5226 AssertRC(rc);
5227 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname);
5228 }
5229 pExtent->uLastGrainAccess = uGrain;
5230 pExtent->uAppendPosition += cbGrain;
5231
5232 return rc;
5233}
5234
5235/**
5236 * Internal: Updates the grain table during a async grain allocation.
5237 */
5238static int vmdkAllocGrainAsyncGTUpdate(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
5239 PVDIOCTX pIoCtx,
5240 PVMDKGRAINALLOCASYNC pGrainAlloc)
5241{
5242 int rc = VINF_SUCCESS;
5243 PVMDKGTCACHE pCache = pImage->pGTCache;
5244 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
5245 uint32_t uGTHash, uGTBlockIndex;
5246 uint64_t uGTSector, uRGTSector, uGTBlock;
5247 uint64_t uSector = pGrainAlloc->uSector;
5248 PVMDKGTCACHEENTRY pGTCacheEntry;
5249
5250 LogFlowFunc(("pImage=%#p pExtent=%#p pCache=%#p pIoCtx=%#p pGrainAlloc=%#p\n",
5251 pImage, pExtent, pCache, pIoCtx, pGrainAlloc));
5252
5253 uGTSector = pGrainAlloc->uGTSector;
5254 uRGTSector = pGrainAlloc->uRGTSector;
5255 LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
5256
5257 /* Update the grain table (and the cache). */
5258 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
5259 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
5260 pGTCacheEntry = &pCache->aGTCache[uGTHash];
5261 if ( pGTCacheEntry->uExtent != pExtent->uExtent
5262 || pGTCacheEntry->uGTBlock != uGTBlock)
5263 {
5264 /* Cache miss, fetch data from disk. */
5265 LogFlow(("Cache miss, fetch data from disk\n"));
5266 PVDMETAXFER pMetaXfer = NULL;
5267 rc = vmdkFileReadMetaAsync(pImage, pExtent->pFile,
5268 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5269 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
5270 &pMetaXfer, vmdkAllocGrainAsyncComplete, pGrainAlloc);
5271 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5272 {
5273 pGrainAlloc->cIoXfersPending++;
5274 pGrainAlloc->fGTUpdateNeeded = true;
5275 /* Leave early, we will be called again after the read completed. */
5276 LogFlowFunc(("Metadata read in progress, leaving\n"));
5277 return rc;
5278 }
5279 else if (RT_FAILURE(rc))
5280 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
5281 vmdkFileMetaXferRelease(pImage, pMetaXfer);
5282 pGTCacheEntry->uExtent = pExtent->uExtent;
5283 pGTCacheEntry->uGTBlock = uGTBlock;
5284 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
5285 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
5286 }
5287 else
5288 {
5289 /* Cache hit. Convert grain table block back to disk format, otherwise
5290 * the code below will write garbage for all but the updated entry. */
5291 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
5292 aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
5293 }
5294 pGrainAlloc->fGTUpdateNeeded = false;
5295 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
5296 aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(pGrainAlloc->uGrainOffset));
5297 pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(pGrainAlloc->uGrainOffset);
5298 /* Update grain table on disk. */
5299 rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
5300 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5301 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
5302 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5303 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5304 pGrainAlloc->cIoXfersPending++;
5305 else if (RT_FAILURE(rc))
5306 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
5307 if (pExtent->pRGD)
5308 {
5309 /* Update backup grain table on disk. */
5310 rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
5311 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5312 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
5313 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5314 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5315 pGrainAlloc->cIoXfersPending++;
5316 else if (RT_FAILURE(rc))
5317 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
5318 }
5319#ifdef VBOX_WITH_VMDK_ESX
5320 if (RT_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
5321 {
5322 pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
5323 pExtent->fMetaDirty = true;
5324 }
5325#endif /* VBOX_WITH_VMDK_ESX */
5326
5327 LogFlowFunc(("leaving rc=%Rrc\n", rc));
5328
5329 return rc;
5330}
5331
5332/**
5333 * Internal - complete the grain allocation by updating disk grain table if required.
5334 */
5335static int vmdkAllocGrainAsyncComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
5336{
5337 int rc = VINF_SUCCESS;
5338 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
5339 PVMDKGRAINALLOCASYNC pGrainAlloc = (PVMDKGRAINALLOCASYNC)pvUser;
5340 PVMDKEXTENT pExtent = pGrainAlloc->pExtent;
5341
5342 LogFlowFunc(("pBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc\n",
5343 pBackendData, pIoCtx, pvUser, rcReq));
5344
5345 pGrainAlloc->cIoXfersPending--;
5346 if (!pGrainAlloc->cIoXfersPending && pGrainAlloc->fGTUpdateNeeded)
5347 rc = vmdkAllocGrainAsyncGTUpdate(pImage, pGrainAlloc->pExtent,
5348 pIoCtx, pGrainAlloc);
5349
5350 if (!pGrainAlloc->cIoXfersPending)
5351 {
5352 /* Grain allocation completed. */
5353 RTMemFree(pGrainAlloc);
5354 }
5355
5356 LogFlowFunc(("Leaving rc=%Rrc\n", rc));
5357 return rc;
5358}
5359
5360/**
5361 * Internal. Allocates a new grain table (if necessary) - async version.
5362 */
5363static int vmdkAllocGrainAsync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
5364 PVDIOCTX pIoCtx, uint64_t uSector,
5365 uint64_t cbWrite)
5366{
5367 PVMDKGTCACHE pCache = pImage->pGTCache;
5368 uint64_t uGDIndex, uGTSector, uRGTSector;
5369 uint64_t uFileOffset;
5370 PVMDKGRAINALLOCASYNC pGrainAlloc = NULL;
5371 int rc;
5372
5373 LogFlowFunc(("pCache=%#p pExtent=%#p pIoCtx=%#p uSector=%llu cbWrite=%llu\n",
5374 pCache, pExtent, pIoCtx, uSector, cbWrite));
5375
5376 AssertReturn(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), VERR_NOT_SUPPORTED);
5377
5378 pGrainAlloc = (PVMDKGRAINALLOCASYNC)RTMemAllocZ(sizeof(VMDKGRAINALLOCASYNC));
5379 if (!pGrainAlloc)
5380 return VERR_NO_MEMORY;
5381
5382 pGrainAlloc->pExtent = pExtent;
5383 pGrainAlloc->uSector = uSector;
5384
5385 uGDIndex = uSector / pExtent->cSectorsPerGDE;
5386 if (uGDIndex >= pExtent->cGDEntries)
5387 {
5388 RTMemFree(pGrainAlloc);
5389 return VERR_OUT_OF_RANGE;
5390 }
5391 uGTSector = pExtent->pGD[uGDIndex];
5392 if (pExtent->pRGD)
5393 uRGTSector = pExtent->pRGD[uGDIndex];
5394 else
5395 uRGTSector = 0; /**< avoid compiler warning */
5396 if (!uGTSector)
5397 {
5398 LogFlow(("Allocating new grain table\n"));
5399
5400 /* There is no grain table referenced by this grain directory
5401 * entry. So there is absolutely no data in this area. Allocate
5402 * a new grain table and put the reference to it in the GDs. */
5403 uFileOffset = pExtent->uAppendPosition;
5404 if (!uFileOffset)
5405 return VERR_INTERNAL_ERROR;
5406 Assert(!(uFileOffset % 512));
5407
5408 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
5409 uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
5410
5411 /* Normally the grain table is preallocated for hosted sparse extents
5412 * that support more than 32 bit sector numbers. So this shouldn't
5413 * ever happen on a valid extent. */
5414 if (uGTSector > UINT32_MAX)
5415 return VERR_VD_VMDK_INVALID_HEADER;
5416
5417 /* Write grain table by writing the required number of grain table
5418 * cache chunks. Allocate memory dynamically here or we flood the
5419 * metadata cache with very small entries. */
5420 size_t cbGTDataTmp = pExtent->cGTEntries * sizeof(uint32_t);
5421 uint32_t *paGTDataTmp = (uint32_t *)RTMemTmpAllocZ(cbGTDataTmp);
5422
5423 if (!paGTDataTmp)
5424 return VERR_NO_MEMORY;
5425
5426 memset(paGTDataTmp, '\0', cbGTDataTmp);
5427 rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
5428 VMDK_SECTOR2BYTE(uGTSector),
5429 paGTDataTmp, cbGTDataTmp, pIoCtx,
5430 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5431 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5432 pGrainAlloc->cIoXfersPending++;
5433 else if (RT_FAILURE(rc))
5434 {
5435 RTMemTmpFree(paGTDataTmp);
5436 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
5437 }
5438 pExtent->uAppendPosition = RT_ALIGN_64( pExtent->uAppendPosition
5439 + cbGTDataTmp, 512);
5440
5441 if (pExtent->pRGD)
5442 {
5443 AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
5444 uFileOffset = pExtent->uAppendPosition;
5445 if (!uFileOffset)
5446 return VERR_INTERNAL_ERROR;
5447 Assert(!(uFileOffset % 512));
5448 uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
5449
5450 /* Normally the redundant grain table is preallocated for hosted
5451 * sparse extents that support more than 32 bit sector numbers. So
5452 * this shouldn't ever happen on a valid extent. */
5453 if (uRGTSector > UINT32_MAX)
5454 {
5455 RTMemTmpFree(paGTDataTmp);
5456 return VERR_VD_VMDK_INVALID_HEADER;
5457 }
5458
5459 /* Write grain table by writing the required number of grain table
5460 * cache chunks. Allocate memory dynamically here or we flood the
5461 * metadata cache with very small entries. */
5462 rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
5463 VMDK_SECTOR2BYTE(uRGTSector),
5464 paGTDataTmp, cbGTDataTmp, pIoCtx,
5465 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5466 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5467 pGrainAlloc->cIoXfersPending++;
5468 else if (RT_FAILURE(rc))
5469 {
5470 RTMemTmpFree(paGTDataTmp);
5471 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
5472 }
5473
5474 pExtent->uAppendPosition = pExtent->uAppendPosition + cbGTDataTmp;
5475 }
5476
5477 RTMemTmpFree(paGTDataTmp);
5478
5479 /* Update the grain directory on disk (doing it before writing the
5480 * grain table will result in a garbled extent if the operation is
5481 * aborted for some reason. Otherwise the worst that can happen is
5482 * some unused sectors in the extent. */
5483 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
5484 rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
5485 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
5486 &uGTSectorLE, sizeof(uGTSectorLE), pIoCtx,
5487 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5488 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5489 pGrainAlloc->cIoXfersPending++;
5490 else if (RT_FAILURE(rc))
5491 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
5492 if (pExtent->pRGD)
5493 {
5494 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
5495 rc = vmdkFileWriteMetaAsync(pImage, pExtent->pFile,
5496 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uGTSectorLE),
5497 &uRGTSectorLE, sizeof(uRGTSectorLE), pIoCtx,
5498 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5499 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5500 pGrainAlloc->cIoXfersPending++;
5501 else if (RT_FAILURE(rc))
5502 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
5503 }
5504
5505 /* As the final step update the in-memory copy of the GDs. */
5506 pExtent->pGD[uGDIndex] = uGTSector;
5507 if (pExtent->pRGD)
5508 pExtent->pRGD[uGDIndex] = uRGTSector;
5509 }
5510
5511 LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
5512 pGrainAlloc->uGTSector = uGTSector;
5513 pGrainAlloc->uRGTSector = uRGTSector;
5514
5515 uFileOffset = pExtent->uAppendPosition;
5516 if (!uFileOffset)
5517 return VERR_INTERNAL_ERROR;
5518 Assert(!(uFileOffset % 512));
5519
5520 pGrainAlloc->uGrainOffset = uFileOffset;
5521
5522 /* Write the data. Always a full grain, or we're in big trouble. */
5523 rc = vmdkFileWriteUserAsync(pImage, pExtent->pFile,
5524 uFileOffset, pIoCtx, cbWrite,
5525 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5526 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5527 pGrainAlloc->cIoXfersPending++;
5528 else if (RT_FAILURE(rc))
5529 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
5530
5531 pExtent->uAppendPosition += cbWrite;
5532
5533 rc = vmdkAllocGrainAsyncGTUpdate(pImage, pExtent, pIoCtx, pGrainAlloc);
5534
5535 if (!pGrainAlloc->cIoXfersPending)
5536 {
5537 /* Grain allocation completed. */
5538 RTMemFree(pGrainAlloc);
5539 }
5540
5541 LogFlowFunc(("leaving rc=%Rrc\n", rc));
5542
5543 return rc;
5544}
5545
5546/**
5547 * Internal. Reads the contents by sequentially going over the compressed
5548 * grains (hoping that they are in sequence).
5549 */
5550static int vmdkStreamReadSequential(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
5551 uint64_t uSector, void *pvBuf,
5552 uint64_t cbRead)
5553{
5554 int rc;
5555
5556 /* Do not allow to go back. */
5557 uint32_t uGrain = uSector / pExtent->cSectorsPerGrain;
5558 if (uGrain < pExtent->uLastGrainAccess)
5559 return VERR_VD_VMDK_INVALID_STATE;
5560 pExtent->uLastGrainAccess = uGrain;
5561
5562 /* After a previous error do not attempt to recover, as it would need
5563 * seeking (in the general case backwards which is forbidden). */
5564 if (!pExtent->uGrainSectorAbs)
5565 return VERR_VD_VMDK_INVALID_STATE;
5566
5567 /* Check if we need to read something from the image or if what we have
5568 * in the buffer is good to fulfill the request. */
5569 if (!pExtent->cbGrainStreamRead || uGrain > pExtent->uGrain)
5570 {
5571 uint32_t uGrainSectorAbs = pExtent->uGrainSectorAbs
5572 + VMDK_BYTE2SECTOR(pExtent->cbGrainStreamRead);
5573
5574 /* Get the marker from the next data block - and skip everything which
5575 * is not a compressed grain. If it's a compressed grain which is for
5576 * the requested sector (or after), read it. */
5577 VMDKMARKER Marker;
5578 do
5579 {
5580 RT_ZERO(Marker);
5581 rc = vmdkFileReadSync(pImage, pExtent->pFile,
5582 VMDK_SECTOR2BYTE(uGrainSectorAbs),
5583 &Marker, RT_OFFSETOF(VMDKMARKER, uType),
5584 NULL);
5585 if (RT_FAILURE(rc))
5586 return rc;
5587 Marker.uSector = RT_LE2H_U64(Marker.uSector);
5588 Marker.cbSize = RT_LE2H_U32(Marker.cbSize);
5589
5590 if (Marker.cbSize == 0)
5591 {
5592 /* A marker for something else than a compressed grain. */
5593 rc = vmdkFileReadSync(pImage, pExtent->pFile,
5594 VMDK_SECTOR2BYTE(uGrainSectorAbs)
5595 + RT_OFFSETOF(VMDKMARKER, uType),
5596 &Marker.uType, sizeof(Marker.uType),
5597 NULL);
5598 if (RT_FAILURE(rc))
5599 return rc;
5600 Marker.uType = RT_LE2H_U32(Marker.uType);
5601 switch (Marker.uType)
5602 {
5603 case VMDK_MARKER_EOS:
5604 uGrainSectorAbs++;
5605 /* Read (or mostly skip) to the end of file. Uses the
5606 * Marker (LBA sector) as it is unused anyway. This
5607 * makes sure that really everything is read in the
5608 * success case. If this read fails it means the image
5609 * is truncated, but this is harmless so ignore. */
5610 vmdkFileReadSync(pImage, pExtent->pFile,
5611 VMDK_SECTOR2BYTE(uGrainSectorAbs)
5612 + 511,
5613 &Marker.uSector, 1, NULL);
5614 break;
5615 case VMDK_MARKER_GT:
5616 uGrainSectorAbs += 1 + VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
5617 break;
5618 case VMDK_MARKER_GD:
5619 uGrainSectorAbs += 1 + VMDK_BYTE2SECTOR(RT_ALIGN(pExtent->cGDEntries * sizeof(uint32_t), 512));
5620 break;
5621 case VMDK_MARKER_FOOTER:
5622 uGrainSectorAbs += 2;
5623 break;
5624 default:
5625 AssertMsgFailed(("VMDK: corrupted marker, type=%#x\n", Marker.uType));
5626 pExtent->uGrainSectorAbs = 0;
5627 return VERR_VD_VMDK_INVALID_STATE;
5628 }
5629 pExtent->cbGrainStreamRead = 0;
5630 }
5631 else
5632 {
5633 /* A compressed grain marker. If it is at/after what we're
5634 * interested in read and decompress data. */
5635 if (uSector > Marker.uSector + pExtent->cSectorsPerGrain)
5636 {
5637 uGrainSectorAbs += VMDK_BYTE2SECTOR(RT_ALIGN(Marker.cbSize + RT_OFFSETOF(VMDKMARKER, uType), 512));
5638 continue;
5639 }
5640 uint64_t uLBA = 0;
5641 uint32_t cbGrainStreamRead = 0;
5642 rc = vmdkFileInflateSync(pImage, pExtent,
5643 VMDK_SECTOR2BYTE(uGrainSectorAbs),
5644 pExtent->pvGrain,
5645 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
5646 &Marker, &uLBA, &cbGrainStreamRead);
5647 if (RT_FAILURE(rc))
5648 {
5649 pExtent->uGrainSectorAbs = 0;
5650 return rc;
5651 }
5652 if ( pExtent->uGrain
5653 && uLBA / pExtent->cSectorsPerGrain <= pExtent->uGrain)
5654 {
5655 pExtent->uGrainSectorAbs = 0;
5656 return VERR_VD_VMDK_INVALID_STATE;
5657 }
5658 pExtent->uGrain = uLBA / pExtent->cSectorsPerGrain;
5659 pExtent->cbGrainStreamRead = cbGrainStreamRead;
5660 break;
5661 }
5662 } while (Marker.uType != VMDK_MARKER_EOS);
5663
5664 pExtent->uGrainSectorAbs = uGrainSectorAbs;
5665
5666 if (!pExtent->cbGrainStreamRead && Marker.uType == VMDK_MARKER_EOS)
5667 {
5668 pExtent->uGrain = UINT32_MAX;
5669 /* Must set a non-zero value for pExtent->cbGrainStreamRead or
5670 * the next read would try to get more data, and we're at EOF. */
5671 pExtent->cbGrainStreamRead = 1;
5672 }
5673 }
5674
5675 if (pExtent->uGrain > uSector / pExtent->cSectorsPerGrain)
5676 {
5677 /* The next data block we have is not for this area, so just return
5678 * that there is no data. */
5679 return VERR_VD_BLOCK_FREE;
5680 }
5681
5682 uint32_t uSectorInGrain = uSector % pExtent->cSectorsPerGrain;
5683 memcpy(pvBuf,
5684 (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain),
5685 cbRead);
5686 return VINF_SUCCESS;
5687}
5688
5689/**
5690 * Replaces a fragment of a string with the specified string.
5691 *
5692 * @returns Pointer to the allocated UTF-8 string.
5693 * @param pszWhere UTF-8 string to search in.
5694 * @param pszWhat UTF-8 string to search for.
5695 * @param pszByWhat UTF-8 string to replace the found string with.
5696 */
5697static char *vmdkStrReplace(const char *pszWhere, const char *pszWhat,
5698 const char *pszByWhat)
5699{
5700 AssertPtr(pszWhere);
5701 AssertPtr(pszWhat);
5702 AssertPtr(pszByWhat);
5703 const char *pszFoundStr = strstr(pszWhere, pszWhat);
5704 if (!pszFoundStr)
5705 return NULL;
5706 size_t cFinal = strlen(pszWhere) + 1 + strlen(pszByWhat) - strlen(pszWhat);
5707 char *pszNewStr = (char *)RTMemAlloc(cFinal);
5708 if (pszNewStr)
5709 {
5710 char *pszTmp = pszNewStr;
5711 memcpy(pszTmp, pszWhere, pszFoundStr - pszWhere);
5712 pszTmp += pszFoundStr - pszWhere;
5713 memcpy(pszTmp, pszByWhat, strlen(pszByWhat));
5714 pszTmp += strlen(pszByWhat);
5715 strcpy(pszTmp, pszFoundStr + strlen(pszWhat));
5716 }
5717 return pszNewStr;
5718}
5719
5720
5721/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
5722static int vmdkCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
5723 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
5724{
5725 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p penmType=%#p\n",
5726 pszFilename, pVDIfsDisk, pVDIfsImage, penmType));
5727 int rc = VINF_SUCCESS;
5728 PVMDKIMAGE pImage;
5729
5730 if ( !pszFilename
5731 || !*pszFilename
5732 || strchr(pszFilename, '"'))
5733 {
5734 rc = VERR_INVALID_PARAMETER;
5735 goto out;
5736 }
5737
5738 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
5739 if (!pImage)
5740 {
5741 rc = VERR_NO_MEMORY;
5742 goto out;
5743 }
5744 pImage->pszFilename = pszFilename;
5745 pImage->pFile = NULL;
5746 pImage->pExtents = NULL;
5747 pImage->pFiles = NULL;
5748 pImage->pGTCache = NULL;
5749 pImage->pDescData = NULL;
5750 pImage->pVDIfsDisk = pVDIfsDisk;
5751 pImage->pVDIfsImage = pVDIfsImage;
5752 /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
5753 * much as possible in vmdkOpenImage. */
5754 rc = vmdkOpenImage(pImage, VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY);
5755 vmdkFreeImage(pImage, false);
5756 RTMemFree(pImage);
5757
5758 if (RT_SUCCESS(rc))
5759 *penmType = VDTYPE_HDD;
5760
5761out:
5762 LogFlowFunc(("returns %Rrc\n", rc));
5763 return rc;
5764}
5765
5766/** @copydoc VBOXHDDBACKEND::pfnOpen */
5767static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
5768 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
5769 VDTYPE enmType, void **ppBackendData)
5770{
5771 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
5772 int rc;
5773 PVMDKIMAGE pImage;
5774
5775 /* Check open flags. All valid flags are supported. */
5776 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
5777 {
5778 rc = VERR_INVALID_PARAMETER;
5779 goto out;
5780 }
5781
5782 /* Check remaining arguments. */
5783 if ( !VALID_PTR(pszFilename)
5784 || !*pszFilename
5785 || strchr(pszFilename, '"'))
5786 {
5787 rc = VERR_INVALID_PARAMETER;
5788 goto out;
5789 }
5790
5791 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
5792 if (!pImage)
5793 {
5794 rc = VERR_NO_MEMORY;
5795 goto out;
5796 }
5797 pImage->pszFilename = pszFilename;
5798 pImage->pFile = NULL;
5799 pImage->pExtents = NULL;
5800 pImage->pFiles = NULL;
5801 pImage->pGTCache = NULL;
5802 pImage->pDescData = NULL;
5803 pImage->pVDIfsDisk = pVDIfsDisk;
5804 pImage->pVDIfsImage = pVDIfsImage;
5805
5806 rc = vmdkOpenImage(pImage, uOpenFlags);
5807 if (RT_SUCCESS(rc))
5808 *ppBackendData = pImage;
5809
5810out:
5811 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
5812 return rc;
5813}
5814
5815/** @copydoc VBOXHDDBACKEND::pfnCreate */
5816static int vmdkCreate(const char *pszFilename, uint64_t cbSize,
5817 unsigned uImageFlags, const char *pszComment,
5818 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
5819 PCRTUUID pUuid, unsigned uOpenFlags,
5820 unsigned uPercentStart, unsigned uPercentSpan,
5821 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
5822 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
5823{
5824 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p ppBackendData=%#p", pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
5825 int rc;
5826 PVMDKIMAGE pImage;
5827
5828 PFNVDPROGRESS pfnProgress = NULL;
5829 void *pvUser = NULL;
5830 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
5831 VDINTERFACETYPE_PROGRESS);
5832 PVDINTERFACEPROGRESS pCbProgress = NULL;
5833 if (pIfProgress)
5834 {
5835 pCbProgress = VDGetInterfaceProgress(pIfProgress);
5836 pfnProgress = pCbProgress->pfnProgress;
5837 pvUser = pIfProgress->pvUser;
5838 }
5839
5840 /* Check open flags. All valid flags are supported. */
5841 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
5842 {
5843 rc = VERR_INVALID_PARAMETER;
5844 goto out;
5845 }
5846
5847 /* Check size. Maximum 2TB-64K for sparse images, otherwise unlimited. */
5848 if ( !cbSize
5849 || (!(uImageFlags & VD_IMAGE_FLAGS_FIXED) && cbSize >= _1T * 2 - _64K))
5850 {
5851 rc = VERR_VD_INVALID_SIZE;
5852 goto out;
5853 }
5854
5855 /* Check remaining arguments. */
5856 if ( !VALID_PTR(pszFilename)
5857 || !*pszFilename
5858 || strchr(pszFilename, '"')
5859 || !VALID_PTR(pPCHSGeometry)
5860 || !VALID_PTR(pLCHSGeometry)
5861#ifndef VBOX_WITH_VMDK_ESX
5862 || ( uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX
5863 && !(uImageFlags & VD_IMAGE_FLAGS_FIXED))
5864#endif
5865 || ( (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
5866 && (uImageFlags & ~(VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED | VD_IMAGE_FLAGS_DIFF))))
5867 {
5868 rc = VERR_INVALID_PARAMETER;
5869 goto out;
5870 }
5871
5872 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
5873 if (!pImage)
5874 {
5875 rc = VERR_NO_MEMORY;
5876 goto out;
5877 }
5878 pImage->pszFilename = pszFilename;
5879 pImage->pFile = NULL;
5880 pImage->pExtents = NULL;
5881 pImage->pFiles = NULL;
5882 pImage->pGTCache = NULL;
5883 pImage->pDescData = NULL;
5884 pImage->pVDIfsDisk = pVDIfsDisk;
5885 pImage->pVDIfsImage = pVDIfsImage;
5886 /* Descriptors for split images can be pretty large, especially if the
5887 * filename is long. So prepare for the worst, and allocate quite some
5888 * memory for the descriptor in this case. */
5889 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
5890 pImage->cbDescAlloc = VMDK_SECTOR2BYTE(200);
5891 else
5892 pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
5893 pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
5894 if (!pImage->pDescData)
5895 {
5896 RTMemFree(pImage);
5897 rc = VERR_NO_MEMORY;
5898 goto out;
5899 }
5900
5901 rc = vmdkCreateImage(pImage, cbSize, uImageFlags, pszComment,
5902 pPCHSGeometry, pLCHSGeometry, pUuid,
5903 pfnProgress, pvUser, uPercentStart, uPercentSpan);
5904 if (RT_SUCCESS(rc))
5905 {
5906 /* So far the image is opened in read/write mode. Make sure the
5907 * image is opened in read-only mode if the caller requested that. */
5908 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
5909 {
5910 vmdkFreeImage(pImage, false);
5911 rc = vmdkOpenImage(pImage, uOpenFlags);
5912 if (RT_FAILURE(rc))
5913 goto out;
5914 }
5915 *ppBackendData = pImage;
5916 }
5917 else
5918 {
5919 RTMemFree(pImage->pDescData);
5920 RTMemFree(pImage);
5921 }
5922
5923out:
5924 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
5925 return rc;
5926}
5927
5928/** @copydoc VBOXHDDBACKEND::pfnRename */
5929static int vmdkRename(void *pBackendData, const char *pszFilename)
5930{
5931 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
5932
5933 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
5934 int rc = VINF_SUCCESS;
5935 char **apszOldName = NULL;
5936 char **apszNewName = NULL;
5937 char **apszNewLines = NULL;
5938 char *pszOldDescName = NULL;
5939 bool fImageFreed = false;
5940 bool fEmbeddedDesc = false;
5941 unsigned cExtents = 0;
5942 char *pszNewBaseName = NULL;
5943 char *pszOldBaseName = NULL;
5944 char *pszNewFullName = NULL;
5945 char *pszOldFullName = NULL;
5946 const char *pszOldImageName;
5947 unsigned i, line;
5948 VMDKDESCRIPTOR DescriptorCopy;
5949 VMDKEXTENT ExtentCopy;
5950
5951 memset(&DescriptorCopy, 0, sizeof(DescriptorCopy));
5952
5953 /* Check arguments. */
5954 if ( !pImage
5955 || (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)
5956 || !VALID_PTR(pszFilename)
5957 || !*pszFilename)
5958 {
5959 rc = VERR_INVALID_PARAMETER;
5960 goto out;
5961 }
5962
5963 cExtents = pImage->cExtents;
5964
5965 /*
5966 * Allocate an array to store both old and new names of renamed files
5967 * in case we have to roll back the changes. Arrays are initialized
5968 * with zeros. We actually save stuff when and if we change it.
5969 */
5970 apszOldName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
5971 apszNewName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
5972 apszNewLines = (char **)RTMemTmpAllocZ((cExtents) * sizeof(char*));
5973 if (!apszOldName || !apszNewName || !apszNewLines)
5974 {
5975 rc = VERR_NO_MEMORY;
5976 goto out;
5977 }
5978
5979 /* Save the descriptor size and position. */
5980 if (pImage->pDescData)
5981 {
5982 /* Separate descriptor file. */
5983 fEmbeddedDesc = false;
5984 }
5985 else
5986 {
5987 /* Embedded descriptor file. */
5988 ExtentCopy = pImage->pExtents[0];
5989 fEmbeddedDesc = true;
5990 }
5991 /* Save the descriptor content. */
5992 DescriptorCopy.cLines = pImage->Descriptor.cLines;
5993 for (i = 0; i < DescriptorCopy.cLines; i++)
5994 {
5995 DescriptorCopy.aLines[i] = RTStrDup(pImage->Descriptor.aLines[i]);
5996 if (!DescriptorCopy.aLines[i])
5997 {
5998 rc = VERR_NO_MEMORY;
5999 goto out;
6000 }
6001 }
6002
6003 /* Prepare both old and new base names used for string replacement. */
6004 pszNewBaseName = RTStrDup(RTPathFilename(pszFilename));
6005 RTPathStripExt(pszNewBaseName);
6006 pszOldBaseName = RTStrDup(RTPathFilename(pImage->pszFilename));
6007 RTPathStripExt(pszOldBaseName);
6008 /* Prepare both old and new full names used for string replacement. */
6009 pszNewFullName = RTStrDup(pszFilename);
6010 RTPathStripExt(pszNewFullName);
6011 pszOldFullName = RTStrDup(pImage->pszFilename);
6012 RTPathStripExt(pszOldFullName);
6013
6014 /* --- Up to this point we have not done any damage yet. --- */
6015
6016 /* Save the old name for easy access to the old descriptor file. */
6017 pszOldDescName = RTStrDup(pImage->pszFilename);
6018 /* Save old image name. */
6019 pszOldImageName = pImage->pszFilename;
6020
6021 /* Update the descriptor with modified extent names. */
6022 for (i = 0, line = pImage->Descriptor.uFirstExtent;
6023 i < cExtents;
6024 i++, line = pImage->Descriptor.aNextLines[line])
6025 {
6026 /* Assume that vmdkStrReplace will fail. */
6027 rc = VERR_NO_MEMORY;
6028 /* Update the descriptor. */
6029 apszNewLines[i] = vmdkStrReplace(pImage->Descriptor.aLines[line],
6030 pszOldBaseName, pszNewBaseName);
6031 if (!apszNewLines[i])
6032 goto rollback;
6033 pImage->Descriptor.aLines[line] = apszNewLines[i];
6034 }
6035 /* Make sure the descriptor gets written back. */
6036 pImage->Descriptor.fDirty = true;
6037 /* Flush the descriptor now, in case it is embedded. */
6038 vmdkFlushImage(pImage);
6039
6040 /* Close and rename/move extents. */
6041 for (i = 0; i < cExtents; i++)
6042 {
6043 PVMDKEXTENT pExtent = &pImage->pExtents[i];
6044 /* Compose new name for the extent. */
6045 apszNewName[i] = vmdkStrReplace(pExtent->pszFullname,
6046 pszOldFullName, pszNewFullName);
6047 if (!apszNewName[i])
6048 goto rollback;
6049 /* Close the extent file. */
6050 vmdkFileClose(pImage, &pExtent->pFile, false);
6051 /* Rename the extent file. */
6052 rc = vmdkFileMove(pImage, pExtent->pszFullname, apszNewName[i], 0);
6053 if (RT_FAILURE(rc))
6054 goto rollback;
6055 /* Remember the old name. */
6056 apszOldName[i] = RTStrDup(pExtent->pszFullname);
6057 }
6058 /* Release all old stuff. */
6059 vmdkFreeImage(pImage, false);
6060
6061 fImageFreed = true;
6062
6063 /* Last elements of new/old name arrays are intended for
6064 * storing descriptor's names.
6065 */
6066 apszNewName[cExtents] = RTStrDup(pszFilename);
6067 /* Rename the descriptor file if it's separate. */
6068 if (!fEmbeddedDesc)
6069 {
6070 rc = vmdkFileMove(pImage, pImage->pszFilename, apszNewName[cExtents], 0);
6071 if (RT_FAILURE(rc))
6072 goto rollback;
6073 /* Save old name only if we may need to change it back. */
6074 apszOldName[cExtents] = RTStrDup(pszFilename);
6075 }
6076
6077 /* Update pImage with the new information. */
6078 pImage->pszFilename = pszFilename;
6079
6080 /* Open the new image. */
6081 rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
6082 if (RT_SUCCESS(rc))
6083 goto out;
6084
6085rollback:
6086 /* Roll back all changes in case of failure. */
6087 if (RT_FAILURE(rc))
6088 {
6089 int rrc;
6090 if (!fImageFreed)
6091 {
6092 /*
6093 * Some extents may have been closed, close the rest. We will
6094 * re-open the whole thing later.
6095 */
6096 vmdkFreeImage(pImage, false);
6097 }
6098 /* Rename files back. */
6099 for (i = 0; i <= cExtents; i++)
6100 {
6101 if (apszOldName[i])
6102 {
6103 rrc = vmdkFileMove(pImage, apszNewName[i], apszOldName[i], 0);
6104 AssertRC(rrc);
6105 }
6106 }
6107 /* Restore the old descriptor. */
6108 PVMDKFILE pFile;
6109 rrc = vmdkFileOpen(pImage, &pFile, pszOldDescName,
6110 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_NORMAL,
6111 false /* fCreate */),
6112 false /* fAsyncIO */);
6113 AssertRC(rrc);
6114 if (fEmbeddedDesc)
6115 {
6116 ExtentCopy.pFile = pFile;
6117 pImage->pExtents = &ExtentCopy;
6118 }
6119 else
6120 {
6121 /* Shouldn't be null for separate descriptor.
6122 * There will be no access to the actual content.
6123 */
6124 pImage->pDescData = pszOldDescName;
6125 pImage->pFile = pFile;
6126 }
6127 pImage->Descriptor = DescriptorCopy;
6128 vmdkWriteDescriptor(pImage);
6129 vmdkFileClose(pImage, &pFile, false);
6130 /* Get rid of the stuff we implanted. */
6131 pImage->pExtents = NULL;
6132 pImage->pFile = NULL;
6133 pImage->pDescData = NULL;
6134 /* Re-open the image back. */
6135 pImage->pszFilename = pszOldImageName;
6136 rrc = vmdkOpenImage(pImage, pImage->uOpenFlags);
6137 AssertRC(rrc);
6138 }
6139
6140out:
6141 for (i = 0; i < DescriptorCopy.cLines; i++)
6142 if (DescriptorCopy.aLines[i])
6143 RTStrFree(DescriptorCopy.aLines[i]);
6144 if (apszOldName)
6145 {
6146 for (i = 0; i <= cExtents; i++)
6147 if (apszOldName[i])
6148 RTStrFree(apszOldName[i]);
6149 RTMemTmpFree(apszOldName);
6150 }
6151 if (apszNewName)
6152 {
6153 for (i = 0; i <= cExtents; i++)
6154 if (apszNewName[i])
6155 RTStrFree(apszNewName[i]);
6156 RTMemTmpFree(apszNewName);
6157 }
6158 if (apszNewLines)
6159 {
6160 for (i = 0; i < cExtents; i++)
6161 if (apszNewLines[i])
6162 RTStrFree(apszNewLines[i]);
6163 RTMemTmpFree(apszNewLines);
6164 }
6165 if (pszOldDescName)
6166 RTStrFree(pszOldDescName);
6167 if (pszOldBaseName)
6168 RTStrFree(pszOldBaseName);
6169 if (pszNewBaseName)
6170 RTStrFree(pszNewBaseName);
6171 if (pszOldFullName)
6172 RTStrFree(pszOldFullName);
6173 if (pszNewFullName)
6174 RTStrFree(pszNewFullName);
6175 LogFlowFunc(("returns %Rrc\n", rc));
6176 return rc;
6177}
6178
6179/** @copydoc VBOXHDDBACKEND::pfnClose */
6180static int vmdkClose(void *pBackendData, bool fDelete)
6181{
6182 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
6183 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6184 int rc;
6185
6186 rc = vmdkFreeImage(pImage, fDelete);
6187 RTMemFree(pImage);
6188
6189 LogFlowFunc(("returns %Rrc\n", rc));
6190 return rc;
6191}
6192
6193/** @copydoc VBOXHDDBACKEND::pfnRead */
6194static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
6195 size_t cbToRead, size_t *pcbActuallyRead)
6196{
6197 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
6198 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6199 PVMDKEXTENT pExtent;
6200 uint64_t uSectorExtentRel;
6201 uint64_t uSectorExtentAbs;
6202 int rc;
6203
6204 AssertPtr(pImage);
6205 Assert(uOffset % 512 == 0);
6206 Assert(cbToRead % 512 == 0);
6207
6208 if ( uOffset + cbToRead > pImage->cbSize
6209 || cbToRead == 0)
6210 {
6211 rc = VERR_INVALID_PARAMETER;
6212 goto out;
6213 }
6214
6215 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
6216 &pExtent, &uSectorExtentRel);
6217 if (RT_FAILURE(rc))
6218 goto out;
6219
6220 /* Check access permissions as defined in the extent descriptor. */
6221 if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
6222 {
6223 rc = VERR_VD_VMDK_INVALID_STATE;
6224 goto out;
6225 }
6226
6227 /* Clip read range to remain in this extent. */
6228 cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6229
6230 /* Handle the read according to the current extent type. */
6231 switch (pExtent->enmType)
6232 {
6233 case VMDKETYPE_HOSTED_SPARSE:
6234#ifdef VBOX_WITH_VMDK_ESX
6235 case VMDKETYPE_ESX_SPARSE:
6236#endif /* VBOX_WITH_VMDK_ESX */
6237 rc = vmdkGetSector(pImage, pExtent, uSectorExtentRel,
6238 &uSectorExtentAbs);
6239 if (RT_FAILURE(rc))
6240 goto out;
6241 /* Clip read range to at most the rest of the grain. */
6242 cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
6243 Assert(!(cbToRead % 512));
6244 if (uSectorExtentAbs == 0)
6245 {
6246 if ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6247 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6248 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
6249 rc = VERR_VD_BLOCK_FREE;
6250 else
6251 rc = vmdkStreamReadSequential(pImage, pExtent,
6252 uSectorExtentRel,
6253 pvBuf, cbToRead);
6254 }
6255 else
6256 {
6257 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6258 {
6259 uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
6260 uSectorExtentAbs -= uSectorInGrain;
6261 uint64_t uLBA;
6262 if (pExtent->uGrainSectorAbs != uSectorExtentAbs)
6263 {
6264 rc = vmdkFileInflateSync(pImage, pExtent,
6265 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6266 pExtent->pvGrain,
6267 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
6268 NULL, &uLBA, NULL);
6269 if (RT_FAILURE(rc))
6270 {
6271 pExtent->uGrainSectorAbs = 0;
6272 AssertRC(rc);
6273 goto out;
6274 }
6275 pExtent->uGrainSectorAbs = uSectorExtentAbs;
6276 pExtent->uGrain = uSectorExtentRel / pExtent->cSectorsPerGrain;
6277 Assert(uLBA == uSectorExtentRel);
6278 }
6279 memcpy(pvBuf, (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), cbToRead);
6280 }
6281 else
6282 {
6283 rc = vmdkFileReadSync(pImage, pExtent->pFile,
6284 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6285 pvBuf, cbToRead, NULL);
6286 }
6287 }
6288 break;
6289 case VMDKETYPE_VMFS:
6290 case VMDKETYPE_FLAT:
6291 rc = vmdkFileReadSync(pImage, pExtent->pFile,
6292 VMDK_SECTOR2BYTE(uSectorExtentRel),
6293 pvBuf, cbToRead, NULL);
6294 break;
6295 case VMDKETYPE_ZERO:
6296 memset(pvBuf, '\0', cbToRead);
6297 break;
6298 }
6299 if (pcbActuallyRead)
6300 *pcbActuallyRead = cbToRead;
6301
6302out:
6303 LogFlowFunc(("returns %Rrc\n", rc));
6304 return rc;
6305}
6306
6307/** @copydoc VBOXHDDBACKEND::pfnWrite */
6308static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
6309 size_t cbToWrite, size_t *pcbWriteProcess,
6310 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
6311{
6312 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
6313 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6314 PVMDKEXTENT pExtent;
6315 uint64_t uSectorExtentRel;
6316 uint64_t uSectorExtentAbs;
6317 int rc;
6318
6319 AssertPtr(pImage);
6320 Assert(uOffset % 512 == 0);
6321 Assert(cbToWrite % 512 == 0);
6322
6323 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6324 {
6325 rc = VERR_VD_IMAGE_READ_ONLY;
6326 goto out;
6327 }
6328
6329 if (cbToWrite == 0)
6330 {
6331 rc = VERR_INVALID_PARAMETER;
6332 goto out;
6333 }
6334
6335 /* No size check here, will do that later when the extent is located.
6336 * There are sparse images out there which according to the spec are
6337 * invalid, because the total size is not a multiple of the grain size.
6338 * Also for sparse images which are stitched together in odd ways (not at
6339 * grain boundaries, and with the nominal size not being a multiple of the
6340 * grain size), this would prevent writing to the last grain. */
6341
6342 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
6343 &pExtent, &uSectorExtentRel);
6344 if (RT_FAILURE(rc))
6345 goto out;
6346
6347 /* Check access permissions as defined in the extent descriptor. */
6348 if ( pExtent->enmAccess != VMDKACCESS_READWRITE
6349 && ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6350 && !pImage->pExtents[0].uAppendPosition
6351 && pExtent->enmAccess != VMDKACCESS_READONLY))
6352 {
6353 rc = VERR_VD_VMDK_INVALID_STATE;
6354 goto out;
6355 }
6356
6357 /* Handle the write according to the current extent type. */
6358 switch (pExtent->enmType)
6359 {
6360 case VMDKETYPE_HOSTED_SPARSE:
6361#ifdef VBOX_WITH_VMDK_ESX
6362 case VMDKETYPE_ESX_SPARSE:
6363#endif /* VBOX_WITH_VMDK_ESX */
6364 rc = vmdkGetSector(pImage, pExtent, uSectorExtentRel,
6365 &uSectorExtentAbs);
6366 if (RT_FAILURE(rc))
6367 goto out;
6368 /* Clip write range to at most the rest of the grain. */
6369 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
6370 if ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
6371 && uSectorExtentRel < (uint64_t)pExtent->uLastGrainAccess * pExtent->cSectorsPerGrain)
6372 {
6373 rc = VERR_VD_VMDK_INVALID_WRITE;
6374 goto out;
6375 }
6376 if (uSectorExtentAbs == 0)
6377 {
6378 if (!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6379 {
6380 if (cbToWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
6381 {
6382 /* Full block write to a previously unallocated block.
6383 * Check if the caller wants feedback. */
6384 if (!(fWrite & VD_WRITE_NO_ALLOC))
6385 {
6386 /* Allocate GT and store the grain. */
6387 rc = vmdkAllocGrain(pImage, pExtent,
6388 uSectorExtentRel,
6389 pvBuf, cbToWrite);
6390 }
6391 else
6392 rc = VERR_VD_BLOCK_FREE;
6393 *pcbPreRead = 0;
6394 *pcbPostRead = 0;
6395 }
6396 else
6397 {
6398 /* Clip write range to remain in this extent. */
6399 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6400 *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
6401 *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbToWrite - *pcbPreRead;
6402 rc = VERR_VD_BLOCK_FREE;
6403 }
6404 }
6405 else
6406 {
6407 rc = vmdkStreamAllocGrain(pImage, pExtent,
6408 uSectorExtentRel,
6409 pvBuf, cbToWrite);
6410 }
6411 }
6412 else
6413 {
6414 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6415 {
6416 /* A partial write to a streamOptimized image is simply
6417 * invalid. It requires rewriting already compressed data
6418 * which is somewhere between expensive and impossible. */
6419 rc = VERR_VD_VMDK_INVALID_STATE;
6420 pExtent->uGrainSectorAbs = 0;
6421 AssertRC(rc);
6422 }
6423 else
6424 {
6425 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
6426 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6427 pvBuf, cbToWrite, NULL);
6428 }
6429 }
6430 break;
6431 case VMDKETYPE_VMFS:
6432 case VMDKETYPE_FLAT:
6433 /* Clip write range to remain in this extent. */
6434 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6435 rc = vmdkFileWriteSync(pImage, pExtent->pFile,
6436 VMDK_SECTOR2BYTE(uSectorExtentRel),
6437 pvBuf, cbToWrite, NULL);
6438 break;
6439 case VMDKETYPE_ZERO:
6440 /* Clip write range to remain in this extent. */
6441 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6442 break;
6443 }
6444
6445 if (pcbWriteProcess)
6446 *pcbWriteProcess = cbToWrite;
6447
6448out:
6449 LogFlowFunc(("returns %Rrc\n", rc));
6450 return rc;
6451}
6452
6453/** @copydoc VBOXHDDBACKEND::pfnFlush */
6454static int vmdkFlush(void *pBackendData)
6455{
6456 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6457 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6458 int rc = VINF_SUCCESS;
6459
6460 AssertPtr(pImage);
6461
6462 if (!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6463 rc = vmdkFlushImage(pImage);
6464
6465 LogFlowFunc(("returns %Rrc\n", rc));
6466 return rc;
6467}
6468
6469/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
6470static unsigned vmdkGetVersion(void *pBackendData)
6471{
6472 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6473 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6474
6475 AssertPtr(pImage);
6476
6477 if (pImage)
6478 return VMDK_IMAGE_VERSION;
6479 else
6480 return 0;
6481}
6482
6483/** @copydoc VBOXHDDBACKEND::pfnGetSize */
6484static uint64_t vmdkGetSize(void *pBackendData)
6485{
6486 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6487 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6488
6489 AssertPtr(pImage);
6490
6491 if (pImage)
6492 return pImage->cbSize;
6493 else
6494 return 0;
6495}
6496
6497/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
6498static uint64_t vmdkGetFileSize(void *pBackendData)
6499{
6500 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6501 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6502 uint64_t cb = 0;
6503
6504 AssertPtr(pImage);
6505
6506 if (pImage)
6507 {
6508 uint64_t cbFile;
6509 if (pImage->pFile != NULL)
6510 {
6511 int rc = vmdkFileGetSize(pImage, pImage->pFile, &cbFile);
6512 if (RT_SUCCESS(rc))
6513 cb += cbFile;
6514 }
6515 for (unsigned i = 0; i < pImage->cExtents; i++)
6516 {
6517 if (pImage->pExtents[i].pFile != NULL)
6518 {
6519 int rc = vmdkFileGetSize(pImage, pImage->pExtents[i].pFile, &cbFile);
6520 if (RT_SUCCESS(rc))
6521 cb += cbFile;
6522 }
6523 }
6524 }
6525
6526 LogFlowFunc(("returns %lld\n", cb));
6527 return cb;
6528}
6529
6530/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
6531static int vmdkGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
6532{
6533 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
6534 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6535 int rc;
6536
6537 AssertPtr(pImage);
6538
6539 if (pImage)
6540 {
6541 if (pImage->PCHSGeometry.cCylinders)
6542 {
6543 *pPCHSGeometry = pImage->PCHSGeometry;
6544 rc = VINF_SUCCESS;
6545 }
6546 else
6547 rc = VERR_VD_GEOMETRY_NOT_SET;
6548 }
6549 else
6550 rc = VERR_VD_NOT_OPENED;
6551
6552 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
6553 return rc;
6554}
6555
6556/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
6557static int vmdkSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
6558{
6559 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
6560 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6561 int rc;
6562
6563 AssertPtr(pImage);
6564
6565 if (pImage)
6566 {
6567 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6568 {
6569 rc = VERR_VD_IMAGE_READ_ONLY;
6570 goto out;
6571 }
6572 if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6573 {
6574 rc = VERR_NOT_SUPPORTED;
6575 goto out;
6576 }
6577 rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
6578 if (RT_FAILURE(rc))
6579 goto out;
6580
6581 pImage->PCHSGeometry = *pPCHSGeometry;
6582 rc = VINF_SUCCESS;
6583 }
6584 else
6585 rc = VERR_VD_NOT_OPENED;
6586
6587out:
6588 LogFlowFunc(("returns %Rrc\n", rc));
6589 return rc;
6590}
6591
6592/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
6593static int vmdkGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
6594{
6595 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
6596 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6597 int rc;
6598
6599 AssertPtr(pImage);
6600
6601 if (pImage)
6602 {
6603 if (pImage->LCHSGeometry.cCylinders)
6604 {
6605 *pLCHSGeometry = pImage->LCHSGeometry;
6606 rc = VINF_SUCCESS;
6607 }
6608 else
6609 rc = VERR_VD_GEOMETRY_NOT_SET;
6610 }
6611 else
6612 rc = VERR_VD_NOT_OPENED;
6613
6614 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
6615 return rc;
6616}
6617
6618/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
6619static int vmdkSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
6620{
6621 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
6622 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6623 int rc;
6624
6625 AssertPtr(pImage);
6626
6627 if (pImage)
6628 {
6629 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6630 {
6631 rc = VERR_VD_IMAGE_READ_ONLY;
6632 goto out;
6633 }
6634 if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6635 {
6636 rc = VERR_NOT_SUPPORTED;
6637 goto out;
6638 }
6639 rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
6640 if (RT_FAILURE(rc))
6641 goto out;
6642
6643 pImage->LCHSGeometry = *pLCHSGeometry;
6644 rc = VINF_SUCCESS;
6645 }
6646 else
6647 rc = VERR_VD_NOT_OPENED;
6648
6649out:
6650 LogFlowFunc(("returns %Rrc\n", rc));
6651 return rc;
6652}
6653
6654/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
6655static unsigned vmdkGetImageFlags(void *pBackendData)
6656{
6657 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6658 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6659 unsigned uImageFlags;
6660
6661 AssertPtr(pImage);
6662
6663 if (pImage)
6664 uImageFlags = pImage->uImageFlags;
6665 else
6666 uImageFlags = 0;
6667
6668 LogFlowFunc(("returns %#x\n", uImageFlags));
6669 return uImageFlags;
6670}
6671
6672/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
6673static unsigned vmdkGetOpenFlags(void *pBackendData)
6674{
6675 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6676 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6677 unsigned uOpenFlags;
6678
6679 AssertPtr(pImage);
6680
6681 if (pImage)
6682 uOpenFlags = pImage->uOpenFlags;
6683 else
6684 uOpenFlags = 0;
6685
6686 LogFlowFunc(("returns %#x\n", uOpenFlags));
6687 return uOpenFlags;
6688}
6689
6690/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
6691static int vmdkSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
6692{
6693 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
6694 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6695 int rc;
6696
6697 /* Image must be opened and the new flags must be valid. */
6698 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
6699 {
6700 rc = VERR_INVALID_PARAMETER;
6701 goto out;
6702 }
6703
6704 /* StreamOptimized images need special treatment: reopen is prohibited. */
6705 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6706 {
6707 if (pImage->uOpenFlags == uOpenFlags)
6708 rc = VINF_SUCCESS;
6709 else
6710 rc = VERR_INVALID_PARAMETER;
6711 goto out;
6712 }
6713
6714 /* Implement this operation via reopening the image. */
6715 vmdkFreeImage(pImage, false);
6716 rc = vmdkOpenImage(pImage, uOpenFlags);
6717
6718out:
6719 LogFlowFunc(("returns %Rrc\n", rc));
6720 return rc;
6721}
6722
6723/** @copydoc VBOXHDDBACKEND::pfnGetComment */
6724static int vmdkGetComment(void *pBackendData, char *pszComment,
6725 size_t cbComment)
6726{
6727 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
6728 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6729 int rc;
6730
6731 AssertPtr(pImage);
6732
6733 if (pImage)
6734 {
6735 const char *pszCommentEncoded = NULL;
6736 rc = vmdkDescDDBGetStr(pImage, &pImage->Descriptor,
6737 "ddb.comment", &pszCommentEncoded);
6738 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
6739 pszCommentEncoded = NULL;
6740 else if (RT_FAILURE(rc))
6741 goto out;
6742
6743 if (pszComment && pszCommentEncoded)
6744 rc = vmdkDecodeString(pszCommentEncoded, pszComment, cbComment);
6745 else
6746 {
6747 if (pszComment)
6748 *pszComment = '\0';
6749 rc = VINF_SUCCESS;
6750 }
6751 if (pszCommentEncoded)
6752 RTStrFree((char *)(void *)pszCommentEncoded);
6753 }
6754 else
6755 rc = VERR_VD_NOT_OPENED;
6756
6757out:
6758 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
6759 return rc;
6760}
6761
6762/** @copydoc VBOXHDDBACKEND::pfnSetComment */
6763static int vmdkSetComment(void *pBackendData, const char *pszComment)
6764{
6765 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
6766 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6767 int rc;
6768
6769 AssertPtr(pImage);
6770
6771 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6772 {
6773 rc = VERR_VD_IMAGE_READ_ONLY;
6774 goto out;
6775 }
6776 if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6777 {
6778 rc = VERR_NOT_SUPPORTED;
6779 goto out;
6780 }
6781
6782 if (pImage)
6783 rc = vmdkSetImageComment(pImage, pszComment);
6784 else
6785 rc = VERR_VD_NOT_OPENED;
6786
6787out:
6788 LogFlowFunc(("returns %Rrc\n", rc));
6789 return rc;
6790}
6791
6792/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
6793static int vmdkGetUuid(void *pBackendData, PRTUUID pUuid)
6794{
6795 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6796 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6797 int rc;
6798
6799 AssertPtr(pImage);
6800
6801 if (pImage)
6802 {
6803 *pUuid = pImage->ImageUuid;
6804 rc = VINF_SUCCESS;
6805 }
6806 else
6807 rc = VERR_VD_NOT_OPENED;
6808
6809 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6810 return rc;
6811}
6812
6813/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
6814static int vmdkSetUuid(void *pBackendData, PCRTUUID pUuid)
6815{
6816 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6817 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6818 int rc;
6819
6820 LogFlowFunc(("%RTuuid\n", pUuid));
6821 AssertPtr(pImage);
6822
6823 if (pImage)
6824 {
6825 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6826 {
6827 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6828 {
6829 pImage->ImageUuid = *pUuid;
6830 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
6831 VMDK_DDB_IMAGE_UUID, pUuid);
6832 if (RT_FAILURE(rc))
6833 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
6834 rc = VINF_SUCCESS;
6835 }
6836 else
6837 rc = VERR_NOT_SUPPORTED;
6838 }
6839 else
6840 rc = VERR_VD_IMAGE_READ_ONLY;
6841 }
6842 else
6843 rc = VERR_VD_NOT_OPENED;
6844
6845 LogFlowFunc(("returns %Rrc\n", rc));
6846 return rc;
6847}
6848
6849/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
6850static int vmdkGetModificationUuid(void *pBackendData, PRTUUID pUuid)
6851{
6852 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6853 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6854 int rc;
6855
6856 AssertPtr(pImage);
6857
6858 if (pImage)
6859 {
6860 *pUuid = pImage->ModificationUuid;
6861 rc = VINF_SUCCESS;
6862 }
6863 else
6864 rc = VERR_VD_NOT_OPENED;
6865
6866 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6867 return rc;
6868}
6869
6870/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
6871static int vmdkSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
6872{
6873 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6874 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6875 int rc;
6876
6877 AssertPtr(pImage);
6878
6879 if (pImage)
6880 {
6881 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6882 {
6883 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6884 {
6885 /* Only touch the modification uuid if it changed. */
6886 if (RTUuidCompare(&pImage->ModificationUuid, pUuid))
6887 {
6888 pImage->ModificationUuid = *pUuid;
6889 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
6890 VMDK_DDB_MODIFICATION_UUID, pUuid);
6891 if (RT_FAILURE(rc))
6892 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename);
6893 }
6894 rc = VINF_SUCCESS;
6895 }
6896 else
6897 rc = VERR_NOT_SUPPORTED;
6898 }
6899 else
6900 rc = VERR_VD_IMAGE_READ_ONLY;
6901 }
6902 else
6903 rc = VERR_VD_NOT_OPENED;
6904
6905 LogFlowFunc(("returns %Rrc\n", rc));
6906 return rc;
6907}
6908
6909/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
6910static int vmdkGetParentUuid(void *pBackendData, PRTUUID pUuid)
6911{
6912 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6913 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6914 int rc;
6915
6916 AssertPtr(pImage);
6917
6918 if (pImage)
6919 {
6920 *pUuid = pImage->ParentUuid;
6921 rc = VINF_SUCCESS;
6922 }
6923 else
6924 rc = VERR_VD_NOT_OPENED;
6925
6926 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6927 return rc;
6928}
6929
6930/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
6931static int vmdkSetParentUuid(void *pBackendData, PCRTUUID pUuid)
6932{
6933 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6934 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6935 int rc;
6936
6937 AssertPtr(pImage);
6938
6939 if (pImage)
6940 {
6941 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6942 {
6943 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6944 {
6945 pImage->ParentUuid = *pUuid;
6946 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
6947 VMDK_DDB_PARENT_UUID, pUuid);
6948 if (RT_FAILURE(rc))
6949 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
6950 rc = VINF_SUCCESS;
6951 }
6952 else
6953 rc = VERR_NOT_SUPPORTED;
6954 }
6955 else
6956 rc = VERR_VD_IMAGE_READ_ONLY;
6957 }
6958 else
6959 rc = VERR_VD_NOT_OPENED;
6960
6961 LogFlowFunc(("returns %Rrc\n", rc));
6962 return rc;
6963}
6964
6965/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
6966static int vmdkGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
6967{
6968 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6969 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6970 int rc;
6971
6972 AssertPtr(pImage);
6973
6974 if (pImage)
6975 {
6976 *pUuid = pImage->ParentModificationUuid;
6977 rc = VINF_SUCCESS;
6978 }
6979 else
6980 rc = VERR_VD_NOT_OPENED;
6981
6982 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6983 return rc;
6984}
6985
6986/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
6987static int vmdkSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
6988{
6989 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6990 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6991 int rc;
6992
6993 AssertPtr(pImage);
6994
6995 if (pImage)
6996 {
6997 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6998 {
6999 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
7000 {
7001 pImage->ParentModificationUuid = *pUuid;
7002 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
7003 VMDK_DDB_PARENT_MODIFICATION_UUID, pUuid);
7004 if (RT_FAILURE(rc))
7005 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
7006 rc = VINF_SUCCESS;
7007 }
7008 else
7009 rc = VERR_NOT_SUPPORTED;
7010 }
7011 else
7012 rc = VERR_VD_IMAGE_READ_ONLY;
7013 }
7014 else
7015 rc = VERR_VD_NOT_OPENED;
7016
7017 LogFlowFunc(("returns %Rrc\n", rc));
7018 return rc;
7019}
7020
7021/** @copydoc VBOXHDDBACKEND::pfnDump */
7022static void vmdkDump(void *pBackendData)
7023{
7024 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
7025
7026 AssertPtr(pImage);
7027 if (pImage)
7028 {
7029 vmdkMessage(pImage, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
7030 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
7031 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
7032 VMDK_BYTE2SECTOR(pImage->cbSize));
7033 vmdkMessage(pImage, "Header: uuidCreation={%RTuuid}\n", &pImage->ImageUuid);
7034 vmdkMessage(pImage, "Header: uuidModification={%RTuuid}\n", &pImage->ModificationUuid);
7035 vmdkMessage(pImage, "Header: uuidParent={%RTuuid}\n", &pImage->ParentUuid);
7036 vmdkMessage(pImage, "Header: uuidParentModification={%RTuuid}\n", &pImage->ParentModificationUuid);
7037 }
7038}
7039
7040/** @copydoc VBOXHDDBACKEND::pfnIsAsyncIOSupported */
7041static bool vmdkIsAsyncIOSupported(void *pBackendData)
7042{
7043 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
7044
7045 /* We do not support async I/O for stream optimized VMDK images. */
7046 return (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) == 0;
7047}
7048
7049/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
7050static int vmdkAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
7051 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
7052{
7053 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
7054 pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
7055 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
7056 PVMDKEXTENT pExtent;
7057 uint64_t uSectorExtentRel;
7058 uint64_t uSectorExtentAbs;
7059 int rc;
7060
7061 AssertPtr(pImage);
7062 Assert(uOffset % 512 == 0);
7063 Assert(cbRead % 512 == 0);
7064
7065 if ( uOffset + cbRead > pImage->cbSize
7066 || cbRead == 0)
7067 {
7068 rc = VERR_INVALID_PARAMETER;
7069 goto out;
7070 }
7071
7072 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
7073 &pExtent, &uSectorExtentRel);
7074 if (RT_FAILURE(rc))
7075 goto out;
7076
7077 /* Check access permissions as defined in the extent descriptor. */
7078 if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
7079 {
7080 rc = VERR_VD_VMDK_INVALID_STATE;
7081 goto out;
7082 }
7083
7084 /* Clip read range to remain in this extent. */
7085 cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
7086
7087 /* Handle the read according to the current extent type. */
7088 switch (pExtent->enmType)
7089 {
7090 case VMDKETYPE_HOSTED_SPARSE:
7091#ifdef VBOX_WITH_VMDK_ESX
7092 case VMDKETYPE_ESX_SPARSE:
7093#endif /* VBOX_WITH_VMDK_ESX */
7094 rc = vmdkGetSectorAsync(pImage, pIoCtx, pExtent,
7095 uSectorExtentRel, &uSectorExtentAbs);
7096 if (RT_FAILURE(rc))
7097 goto out;
7098 /* Clip read range to at most the rest of the grain. */
7099 cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
7100 Assert(!(cbRead % 512));
7101 if (uSectorExtentAbs == 0)
7102 rc = VERR_VD_BLOCK_FREE;
7103 else
7104 {
7105 AssertMsg(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), ("Async I/O is not supported for stream optimized VMDK's\n"));
7106 rc = vmdkFileReadUserAsync(pImage, pExtent->pFile,
7107 VMDK_SECTOR2BYTE(uSectorExtentAbs),
7108 pIoCtx, cbRead);
7109 }
7110 break;
7111 case VMDKETYPE_VMFS:
7112 case VMDKETYPE_FLAT:
7113 rc = vmdkFileReadUserAsync(pImage, pExtent->pFile,
7114 VMDK_SECTOR2BYTE(uSectorExtentRel),
7115 pIoCtx, cbRead);
7116 break;
7117 case VMDKETYPE_ZERO:
7118 size_t cbSet;
7119
7120 cbSet = vmdkFileIoCtxSet(pImage, pIoCtx, 0, cbRead);
7121 Assert(cbSet == cbRead);
7122
7123 rc = VINF_SUCCESS;
7124 break;
7125 }
7126 if (pcbActuallyRead)
7127 *pcbActuallyRead = cbRead;
7128
7129out:
7130 LogFlowFunc(("returns %Rrc\n", rc));
7131 return rc;
7132}
7133
7134/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
7135static int vmdkAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
7136 PVDIOCTX pIoCtx,
7137 size_t *pcbWriteProcess, size_t *pcbPreRead,
7138 size_t *pcbPostRead, unsigned fWrite)
7139{
7140 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
7141 pBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
7142 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
7143 PVMDKEXTENT pExtent;
7144 uint64_t uSectorExtentRel;
7145 uint64_t uSectorExtentAbs;
7146 int rc;
7147
7148 AssertPtr(pImage);
7149 Assert(uOffset % 512 == 0);
7150 Assert(cbWrite % 512 == 0);
7151
7152 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
7153 {
7154 rc = VERR_VD_IMAGE_READ_ONLY;
7155 goto out;
7156 }
7157
7158 if (cbWrite == 0)
7159 {
7160 rc = VERR_INVALID_PARAMETER;
7161 goto out;
7162 }
7163
7164 /* No size check here, will do that later when the extent is located.
7165 * There are sparse images out there which according to the spec are
7166 * invalid, because the total size is not a multiple of the grain size.
7167 * Also for sparse images which are stitched together in odd ways (not at
7168 * grain boundaries, and with the nominal size not being a multiple of the
7169 * grain size), this would prevent writing to the last grain. */
7170
7171 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
7172 &pExtent, &uSectorExtentRel);
7173 if (RT_FAILURE(rc))
7174 goto out;
7175
7176 /* Check access permissions as defined in the extent descriptor. */
7177 if (pExtent->enmAccess != VMDKACCESS_READWRITE)
7178 {
7179 rc = VERR_VD_VMDK_INVALID_STATE;
7180 goto out;
7181 }
7182
7183 /* Handle the write according to the current extent type. */
7184 switch (pExtent->enmType)
7185 {
7186 case VMDKETYPE_HOSTED_SPARSE:
7187#ifdef VBOX_WITH_VMDK_ESX
7188 case VMDKETYPE_ESX_SPARSE:
7189#endif /* VBOX_WITH_VMDK_ESX */
7190 rc = vmdkGetSectorAsync(pImage, pIoCtx, pExtent, uSectorExtentRel,
7191 &uSectorExtentAbs);
7192 if (RT_FAILURE(rc))
7193 goto out;
7194 /* Clip write range to at most the rest of the grain. */
7195 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
7196 if ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
7197 && uSectorExtentRel < (uint64_t)pExtent->uLastGrainAccess * pExtent->cSectorsPerGrain)
7198 {
7199 rc = VERR_VD_VMDK_INVALID_WRITE;
7200 goto out;
7201 }
7202 if (uSectorExtentAbs == 0)
7203 {
7204 if (cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
7205 {
7206 /* Full block write to a previously unallocated block.
7207 * Check if the caller wants to avoid the automatic alloc. */
7208 if (!(fWrite & VD_WRITE_NO_ALLOC))
7209 {
7210 /* Allocate GT and find out where to store the grain. */
7211 rc = vmdkAllocGrainAsync(pImage, pExtent, pIoCtx,
7212 uSectorExtentRel, cbWrite);
7213 }
7214 else
7215 rc = VERR_VD_BLOCK_FREE;
7216 *pcbPreRead = 0;
7217 *pcbPostRead = 0;
7218 }
7219 else
7220 {
7221 /* Clip write range to remain in this extent. */
7222 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
7223 *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
7224 *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite - *pcbPreRead;
7225 rc = VERR_VD_BLOCK_FREE;
7226 }
7227 }
7228 else
7229 {
7230 Assert(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED));
7231 rc = vmdkFileWriteUserAsync(pImage, pExtent->pFile,
7232 VMDK_SECTOR2BYTE(uSectorExtentAbs),
7233 pIoCtx, cbWrite, NULL, NULL);
7234 }
7235 break;
7236 case VMDKETYPE_VMFS:
7237 case VMDKETYPE_FLAT:
7238 /* Clip write range to remain in this extent. */
7239 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
7240 rc = vmdkFileWriteUserAsync(pImage, pExtent->pFile,
7241 VMDK_SECTOR2BYTE(uSectorExtentRel),
7242 pIoCtx, cbWrite, NULL, NULL);
7243 break;
7244 case VMDKETYPE_ZERO:
7245 /* Clip write range to remain in this extent. */
7246 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
7247 break;
7248 }
7249
7250 if (pcbWriteProcess)
7251 *pcbWriteProcess = cbWrite;
7252
7253out:
7254 LogFlowFunc(("returns %Rrc\n", rc));
7255 return rc;
7256}
7257
7258/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
7259static int vmdkAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
7260{
7261 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
7262 PVMDKEXTENT pExtent;
7263 int rc = VINF_SUCCESS;
7264
7265 for (unsigned i = 0; i < pImage->cExtents; i++)
7266 {
7267 pExtent = &pImage->pExtents[i];
7268 if (pExtent->pFile != NULL && pExtent->fMetaDirty)
7269 {
7270 switch (pExtent->enmType)
7271 {
7272 case VMDKETYPE_HOSTED_SPARSE:
7273#ifdef VBOX_WITH_VMDK_ESX
7274 case VMDKETYPE_ESX_SPARSE:
7275#endif /* VBOX_WITH_VMDK_ESX */
7276 rc = vmdkWriteMetaSparseExtentAsync(pImage, pExtent, 0, pIoCtx);
7277 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
7278 goto out;
7279 if (pExtent->fFooter)
7280 {
7281 uint64_t uFileOffset = pExtent->uAppendPosition;
7282 if (!uFileOffset)
7283 {
7284 rc = VERR_INTERNAL_ERROR;
7285 goto out;
7286 }
7287 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
7288 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
7289 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
7290 goto out;
7291 }
7292 break;
7293 case VMDKETYPE_VMFS:
7294 case VMDKETYPE_FLAT:
7295 /* Nothing to do. */
7296 break;
7297 case VMDKETYPE_ZERO:
7298 default:
7299 AssertMsgFailed(("extent with type %d marked as dirty\n",
7300 pExtent->enmType));
7301 break;
7302 }
7303 }
7304 switch (pExtent->enmType)
7305 {
7306 case VMDKETYPE_HOSTED_SPARSE:
7307#ifdef VBOX_WITH_VMDK_ESX
7308 case VMDKETYPE_ESX_SPARSE:
7309#endif /* VBOX_WITH_VMDK_ESX */
7310 case VMDKETYPE_VMFS:
7311 case VMDKETYPE_FLAT:
7312 /*
7313 * Don't ignore block devices like in the sync case
7314 * (they have an absolute path).
7315 * We might have unwritten data in the writeback cache and
7316 * the async I/O manager will handle these requests properly
7317 * even if the block device doesn't support these requests.
7318 */
7319 if ( pExtent->pFile != NULL
7320 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
7321 rc = vmdkFileFlushAsync(pImage, pExtent->pFile, pIoCtx);
7322 break;
7323 case VMDKETYPE_ZERO:
7324 /* No need to do anything for this extent. */
7325 break;
7326 default:
7327 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
7328 break;
7329 }
7330 }
7331
7332out:
7333 return rc;
7334}
7335
7336
7337VBOXHDDBACKEND g_VmdkBackend =
7338{
7339 /* pszBackendName */
7340 "VMDK",
7341 /* cbSize */
7342 sizeof(VBOXHDDBACKEND),
7343 /* uBackendCaps */
7344 VD_CAP_UUID | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC
7345 | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE | VD_CAP_ASYNC
7346 | VD_CAP_VFS,
7347 /* paFileExtensions */
7348 s_aVmdkFileExtensions,
7349 /* paConfigInfo */
7350 NULL,
7351 /* hPlugin */
7352 NIL_RTLDRMOD,
7353 /* pfnCheckIfValid */
7354 vmdkCheckIfValid,
7355 /* pfnOpen */
7356 vmdkOpen,
7357 /* pfnCreate */
7358 vmdkCreate,
7359 /* pfnRename */
7360 vmdkRename,
7361 /* pfnClose */
7362 vmdkClose,
7363 /* pfnRead */
7364 vmdkRead,
7365 /* pfnWrite */
7366 vmdkWrite,
7367 /* pfnFlush */
7368 vmdkFlush,
7369 /* pfnGetVersion */
7370 vmdkGetVersion,
7371 /* pfnGetSize */
7372 vmdkGetSize,
7373 /* pfnGetFileSize */
7374 vmdkGetFileSize,
7375 /* pfnGetPCHSGeometry */
7376 vmdkGetPCHSGeometry,
7377 /* pfnSetPCHSGeometry */
7378 vmdkSetPCHSGeometry,
7379 /* pfnGetLCHSGeometry */
7380 vmdkGetLCHSGeometry,
7381 /* pfnSetLCHSGeometry */
7382 vmdkSetLCHSGeometry,
7383 /* pfnGetImageFlags */
7384 vmdkGetImageFlags,
7385 /* pfnGetOpenFlags */
7386 vmdkGetOpenFlags,
7387 /* pfnSetOpenFlags */
7388 vmdkSetOpenFlags,
7389 /* pfnGetComment */
7390 vmdkGetComment,
7391 /* pfnSetComment */
7392 vmdkSetComment,
7393 /* pfnGetUuid */
7394 vmdkGetUuid,
7395 /* pfnSetUuid */
7396 vmdkSetUuid,
7397 /* pfnGetModificationUuid */
7398 vmdkGetModificationUuid,
7399 /* pfnSetModificationUuid */
7400 vmdkSetModificationUuid,
7401 /* pfnGetParentUuid */
7402 vmdkGetParentUuid,
7403 /* pfnSetParentUuid */
7404 vmdkSetParentUuid,
7405 /* pfnGetParentModificationUuid */
7406 vmdkGetParentModificationUuid,
7407 /* pfnSetParentModificationUuid */
7408 vmdkSetParentModificationUuid,
7409 /* pfnDump */
7410 vmdkDump,
7411 /* pfnGetTimeStamp */
7412 NULL,
7413 /* pfnGetParentTimeStamp */
7414 NULL,
7415 /* pfnSetParentTimeStamp */
7416 NULL,
7417 /* pfnGetParentFilename */
7418 NULL,
7419 /* pfnSetParentFilename */
7420 NULL,
7421 /* pfnIsAsyncIOSupported */
7422 vmdkIsAsyncIOSupported,
7423 /* pfnAsyncRead */
7424 vmdkAsyncRead,
7425 /* pfnAsyncWrite */
7426 vmdkAsyncWrite,
7427 /* pfnAsyncFlush */
7428 vmdkAsyncFlush,
7429 /* pfnComposeLocation */
7430 genericFileComposeLocation,
7431 /* pfnComposeName */
7432 genericFileComposeName,
7433 /* pfnCompact */
7434 NULL,
7435 /* pfnResize */
7436 NULL
7437};
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