VirtualBox

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

Last change on this file since 38623 was 38621, checked in by vboxsync, 13 years ago

VD: Initial support to discard unused blocks in an image + support for VDI images

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