VirtualBox

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

Last change on this file since 38521 was 38469, checked in by vboxsync, 13 years ago

VD: Interface cleanup. Merge the two involved structures (generic interface descriptor and callback table) into one, remove the duplicated interface wrappers in the backends and move the interface definitions into separate headers separating public and private interfaces.

  • 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 38469 2011-08-16 10:34:32Z 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};
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