VirtualBox

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

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

Storage/VMDK: fixed progress indicator

  • 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 38693 2011-09-08 19:21:45Z 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 + (cbOffset + uOff) * uPercentSpan / cbSize);
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 cbOffset += cbExtent;
3831
3832 if (RT_SUCCESS(rc) && pfnProgress)
3833 pfnProgress(pvUser, uPercentStart + cbOffset * uPercentSpan / cbSize);
3834
3835 cbRemaining -= cbExtent;
3836 }
3837
3838 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
3839 {
3840 /* VirtualBox doesn't care, but VMWare ESX freaks out if the wrong
3841 * controller type is set in an image. */
3842 rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor, "ddb.adapterType", "lsilogic");
3843 if (RT_FAILURE(rc))
3844 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set controller type to lsilogic in '%s'"), pImage->pszFilename);
3845 }
3846
3847 const char *pszDescType = NULL;
3848 if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
3849 {
3850 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX)
3851 pszDescType = "vmfs";
3852 else
3853 pszDescType = (cExtents == 1)
3854 ? "monolithicFlat" : "twoGbMaxExtentFlat";
3855 }
3856 else
3857 {
3858 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
3859 pszDescType = "streamOptimized";
3860 else
3861 {
3862 pszDescType = (cExtents == 1)
3863 ? "monolithicSparse" : "twoGbMaxExtentSparse";
3864 }
3865 }
3866 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
3867 pszDescType);
3868 if (RT_FAILURE(rc))
3869 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
3870 return rc;
3871}
3872
3873/**
3874 * Internal: Create a real stream optimized VMDK using only linear writes.
3875 */
3876static int vmdkCreateStreamImage(PVMDKIMAGE pImage, uint64_t cbSize,
3877 unsigned uImageFlags,
3878 PFNVDPROGRESS pfnProgress, void *pvUser,
3879 unsigned uPercentStart, unsigned uPercentSpan)
3880{
3881 int rc;
3882
3883 rc = vmdkCreateExtents(pImage, 1);
3884 if (RT_FAILURE(rc))
3885 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
3886
3887 /* Basename strings needed for constructing the extent names. */
3888 const char *pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
3889 AssertPtr(pszBasenameSubstr);
3890 size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
3891
3892 /* No separate descriptor file. */
3893 pImage->pFile = NULL;
3894
3895 /* Set up all extents. */
3896 PVMDKEXTENT pExtent = &pImage->pExtents[0];
3897
3898 /* Set up fullname/basename for extent description. Cannot use StrDup
3899 * for basename, as it is not guaranteed that the memory can be freed
3900 * with RTMemTmpFree, which must be used as in other code paths
3901 * StrDup is not usable. */
3902 char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
3903 if (!pszBasename)
3904 return VERR_NO_MEMORY;
3905 memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
3906 pExtent->pszBasename = pszBasename;
3907
3908 char *pszBasedirectory = RTStrDup(pImage->pszFilename);
3909 RTPathStripFilename(pszBasedirectory);
3910 char *pszFullname = RTPathJoinA(pszBasedirectory, pExtent->pszBasename);
3911 RTStrFree(pszBasedirectory);
3912 if (!pszFullname)
3913 return VERR_NO_STR_MEMORY;
3914 pExtent->pszFullname = pszFullname;
3915
3916 /* Create file for extent. Make it write only, no reading allowed. */
3917 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
3918 VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
3919 true /* fCreate */)
3920 & ~RTFILE_O_READ,
3921 false /* fAsyncIO */);
3922 if (RT_FAILURE(rc))
3923 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
3924
3925 /* Place descriptor file information. */
3926 pExtent->uDescriptorSector = 1;
3927 pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
3928 /* The descriptor is part of the (only) extent. */
3929 pExtent->pDescData = pImage->pDescData;
3930 pImage->pDescData = NULL;
3931
3932 uint64_t cSectorsPerGDE, cSectorsPerGD;
3933 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
3934 pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, _64K));
3935 pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K);
3936 pExtent->cGTEntries = 512;
3937 cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
3938 pExtent->cSectorsPerGDE = cSectorsPerGDE;
3939 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
3940 cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
3941
3942 /* The spec says version is 1 for all VMDKs, but the vast
3943 * majority of streamOptimized VMDKs actually contain
3944 * version 3 - so go with the majority. Both are accepted. */
3945 pExtent->uVersion = 3;
3946 pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
3947 pExtent->fFooter = true;
3948
3949 pExtent->enmAccess = VMDKACCESS_READONLY;
3950 pExtent->fUncleanShutdown = false;
3951 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
3952 pExtent->uSectorOffset = 0;
3953 pExtent->fMetaDirty = true;
3954
3955 /* Create grain directory, without preallocating it straight away. It will
3956 * be constructed on the fly when writing out the data and written when
3957 * closing the image. The end effect is that the full grain directory is
3958 * allocated, which is a requirement of the VMDK specs. */
3959 rc = vmdkCreateGrainDirectory(pImage, pExtent, VMDK_GD_AT_END,
3960 false /* fPreAlloc */);
3961 if (RT_FAILURE(rc))
3962 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
3963
3964 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
3965 "streamOptimized");
3966 if (RT_FAILURE(rc))
3967 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
3968
3969 return rc;
3970}
3971
3972/**
3973 * Internal: The actual code for creating any VMDK variant currently in
3974 * existence on hosted environments.
3975 */
3976static int vmdkCreateImage(PVMDKIMAGE pImage, uint64_t cbSize,
3977 unsigned uImageFlags, const char *pszComment,
3978 PCVDGEOMETRY pPCHSGeometry,
3979 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
3980 PFNVDPROGRESS pfnProgress, void *pvUser,
3981 unsigned uPercentStart, unsigned uPercentSpan)
3982{
3983 int rc;
3984
3985 pImage->uImageFlags = uImageFlags;
3986
3987 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
3988 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
3989 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
3990
3991 rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
3992 &pImage->Descriptor);
3993 if (RT_FAILURE(rc))
3994 {
3995 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
3996 goto out;
3997 }
3998
3999 if ( (uImageFlags & VD_IMAGE_FLAGS_FIXED)
4000 && (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
4001 {
4002 /* Raw disk image (includes raw partition). */
4003 const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment;
4004 /* As the comment is misused, zap it so that no garbage comment
4005 * is set below. */
4006 pszComment = NULL;
4007 rc = vmdkCreateRawImage(pImage, pRaw, cbSize);
4008 }
4009 else
4010 {
4011 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4012 {
4013 /* Stream optimized sparse image (monolithic). */
4014 rc = vmdkCreateStreamImage(pImage, cbSize, uImageFlags,
4015 pfnProgress, pvUser, uPercentStart,
4016 uPercentSpan * 95 / 100);
4017 }
4018 else
4019 {
4020 /* Regular fixed or sparse image (monolithic or split). */
4021 rc = vmdkCreateRegularImage(pImage, cbSize, uImageFlags,
4022 pfnProgress, pvUser, uPercentStart,
4023 uPercentSpan * 95 / 100);
4024 }
4025 }
4026
4027 if (RT_FAILURE(rc))
4028 goto out;
4029
4030 if (RT_SUCCESS(rc) && pfnProgress)
4031 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
4032
4033 pImage->cbSize = cbSize;
4034
4035 for (unsigned i = 0; i < pImage->cExtents; i++)
4036 {
4037 PVMDKEXTENT pExtent = &pImage->pExtents[i];
4038
4039 rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
4040 pExtent->cNominalSectors, pExtent->enmType,
4041 pExtent->pszBasename, pExtent->uSectorOffset);
4042 if (RT_FAILURE(rc))
4043 {
4044 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
4045 goto out;
4046 }
4047 }
4048 vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
4049
4050 if ( pPCHSGeometry->cCylinders != 0
4051 && pPCHSGeometry->cHeads != 0
4052 && pPCHSGeometry->cSectors != 0)
4053 {
4054 rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
4055 if (RT_FAILURE(rc))
4056 goto out;
4057 }
4058 if ( pLCHSGeometry->cCylinders != 0
4059 && pLCHSGeometry->cHeads != 0
4060 && pLCHSGeometry->cSectors != 0)
4061 {
4062 rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
4063 if (RT_FAILURE(rc))
4064 goto out;
4065 }
4066
4067 pImage->LCHSGeometry = *pLCHSGeometry;
4068 pImage->PCHSGeometry = *pPCHSGeometry;
4069
4070 pImage->ImageUuid = *pUuid;
4071 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4072 VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
4073 if (RT_FAILURE(rc))
4074 {
4075 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
4076 goto out;
4077 }
4078 RTUuidClear(&pImage->ParentUuid);
4079 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4080 VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
4081 if (RT_FAILURE(rc))
4082 {
4083 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pImage->pszFilename);
4084 goto out;
4085 }
4086 RTUuidClear(&pImage->ModificationUuid);
4087 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4088 VMDK_DDB_MODIFICATION_UUID,
4089 &pImage->ModificationUuid);
4090 if (RT_FAILURE(rc))
4091 {
4092 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pImage->pszFilename);
4093 goto out;
4094 }
4095 RTUuidClear(&pImage->ParentModificationUuid);
4096 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
4097 VMDK_DDB_PARENT_MODIFICATION_UUID,
4098 &pImage->ParentModificationUuid);
4099 if (RT_FAILURE(rc))
4100 {
4101 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in new descriptor in '%s'"), pImage->pszFilename);
4102 goto out;
4103 }
4104
4105 rc = vmdkAllocateGrainTableCache(pImage);
4106 if (RT_FAILURE(rc))
4107 goto out;
4108
4109 rc = vmdkSetImageComment(pImage, pszComment);
4110 if (RT_FAILURE(rc))
4111 {
4112 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
4113 goto out;
4114 }
4115
4116 if (RT_SUCCESS(rc) && pfnProgress)
4117 pfnProgress(pvUser, uPercentStart + uPercentSpan * 99 / 100);
4118
4119 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4120 {
4121 /* streamOptimized is a bit special, we cannot trigger the flush
4122 * until all data has been written. So we write the necessary
4123 * information explicitly. */
4124 pImage->pExtents[0].cDescriptorSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64( pImage->Descriptor.aLines[pImage->Descriptor.cLines]
4125 - pImage->Descriptor.aLines[0], 512));
4126 rc = vmdkWriteMetaSparseExtent(pImage, &pImage->pExtents[0], 0);
4127 if (RT_FAILURE(rc))
4128 {
4129 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK header in '%s'"), pImage->pszFilename);
4130 goto out;
4131 }
4132
4133 rc = vmdkWriteDescriptor(pImage);
4134 if (RT_FAILURE(rc))
4135 {
4136 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK descriptor in '%s'"), pImage->pszFilename);
4137 goto out;
4138 }
4139 }
4140 else
4141 rc = vmdkFlushImage(pImage);
4142
4143out:
4144 if (RT_SUCCESS(rc) && pfnProgress)
4145 pfnProgress(pvUser, uPercentStart + uPercentSpan);
4146
4147 if (RT_FAILURE(rc))
4148 vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
4149 return rc;
4150}
4151
4152/**
4153 * Internal: Update image comment.
4154 */
4155static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment)
4156{
4157 char *pszCommentEncoded;
4158 if (pszComment)
4159 {
4160 pszCommentEncoded = vmdkEncodeString(pszComment);
4161 if (!pszCommentEncoded)
4162 return VERR_NO_MEMORY;
4163 }
4164 else
4165 pszCommentEncoded = NULL;
4166 int rc = vmdkDescDDBSetStr(pImage, &pImage->Descriptor,
4167 "ddb.comment", pszCommentEncoded);
4168 if (pszComment)
4169 RTStrFree(pszCommentEncoded);
4170 if (RT_FAILURE(rc))
4171 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing image comment in descriptor in '%s'"), pImage->pszFilename);
4172 return VINF_SUCCESS;
4173}
4174
4175/**
4176 * Internal. Clear the grain table buffer for real stream optimized writing.
4177 */
4178static void vmdkStreamClearGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
4179{
4180 uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
4181 for (uint32_t i = 0; i < cCacheLines; i++)
4182 memset(&pImage->pGTCache->aGTCache[i].aGTData[0], '\0',
4183 VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t));
4184}
4185
4186/**
4187 * Internal. Flush the grain table buffer for real stream optimized writing.
4188 */
4189static int vmdkStreamFlushGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4190 uint32_t uGDEntry)
4191{
4192 int rc = VINF_SUCCESS;
4193 uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
4194
4195 /* VMware does not write out completely empty grain tables in the case
4196 * of streamOptimized images, which according to my interpretation of
4197 * the VMDK 1.1 spec is bending the rules. Since they do it and we can
4198 * handle it without problems do it the same way and save some bytes. */
4199 bool fAllZero = true;
4200 for (uint32_t i = 0; i < cCacheLines; i++)
4201 {
4202 /* Convert the grain table to little endian in place, as it will not
4203 * be used at all after this function has been called. */
4204 uint32_t *pGTTmp = &pImage->pGTCache->aGTCache[i].aGTData[0];
4205 for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
4206 if (*pGTTmp)
4207 {
4208 fAllZero = false;
4209 break;
4210 }
4211 if (!fAllZero)
4212 break;
4213 }
4214 if (fAllZero)
4215 return VINF_SUCCESS;
4216
4217 uint64_t uFileOffset = pExtent->uAppendPosition;
4218 if (!uFileOffset)
4219 return VERR_INTERNAL_ERROR;
4220 /* Align to sector, as the previous write could have been any size. */
4221 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4222
4223 /* Grain table marker. */
4224 uint8_t aMarker[512];
4225 PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
4226 memset(pMarker, '\0', sizeof(aMarker));
4227 pMarker->uSector = RT_H2LE_U64(VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t)));
4228 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GT);
4229 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, uFileOffset,
4230 aMarker, sizeof(aMarker), NULL);
4231 AssertRC(rc);
4232 uFileOffset += 512;
4233
4234 if (!pExtent->pGD || pExtent->pGD[uGDEntry])
4235 return VERR_INTERNAL_ERROR;
4236
4237 pExtent->pGD[uGDEntry] = VMDK_BYTE2SECTOR(uFileOffset);
4238
4239 for (uint32_t i = 0; i < cCacheLines; i++)
4240 {
4241 /* Convert the grain table to little endian in place, as it will not
4242 * be used at all after this function has been called. */
4243 uint32_t *pGTTmp = &pImage->pGTCache->aGTCache[i].aGTData[0];
4244 for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
4245 *pGTTmp = RT_H2LE_U32(*pGTTmp);
4246
4247 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, uFileOffset,
4248 &pImage->pGTCache->aGTCache[i].aGTData[0],
4249 VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t),
4250 NULL);
4251 uFileOffset += VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t);
4252 if (RT_FAILURE(rc))
4253 break;
4254 }
4255 Assert(!(uFileOffset % 512));
4256 pExtent->uAppendPosition = RT_ALIGN_64(uFileOffset, 512);
4257 return rc;
4258}
4259
4260/**
4261 * Internal. Free all allocated space for representing an image, and optionally
4262 * delete the image from disk.
4263 */
4264static int vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete)
4265{
4266 int rc = VINF_SUCCESS;
4267
4268 /* Freeing a never allocated image (e.g. because the open failed) is
4269 * not signalled as an error. After all nothing bad happens. */
4270 if (pImage)
4271 {
4272 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
4273 {
4274 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4275 {
4276 /* Check if all extents are clean. */
4277 for (unsigned i = 0; i < pImage->cExtents; i++)
4278 {
4279 Assert(!pImage->pExtents[i].fUncleanShutdown);
4280 }
4281 }
4282 else
4283 {
4284 /* Mark all extents as clean. */
4285 for (unsigned i = 0; i < pImage->cExtents; i++)
4286 {
4287 if ( ( pImage->pExtents[i].enmType == VMDKETYPE_HOSTED_SPARSE
4288#ifdef VBOX_WITH_VMDK_ESX
4289 || pImage->pExtents[i].enmType == VMDKETYPE_ESX_SPARSE
4290#endif /* VBOX_WITH_VMDK_ESX */
4291 )
4292 && pImage->pExtents[i].fUncleanShutdown)
4293 {
4294 pImage->pExtents[i].fUncleanShutdown = false;
4295 pImage->pExtents[i].fMetaDirty = true;
4296 }
4297
4298 /* From now on it's not safe to append any more data. */
4299 pImage->pExtents[i].uAppendPosition = 0;
4300 }
4301 }
4302 }
4303
4304 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4305 {
4306 /* No need to write any pending data if the file will be deleted
4307 * or if the new file wasn't successfully created. */
4308 if ( !fDelete && pImage->pExtents
4309 && pImage->pExtents[0].cGTEntries
4310 && pImage->pExtents[0].uAppendPosition)
4311 {
4312 PVMDKEXTENT pExtent = &pImage->pExtents[0];
4313 uint32_t uLastGDEntry = pExtent->uLastGrainAccess / pExtent->cGTEntries;
4314 rc = vmdkStreamFlushGT(pImage, pExtent, uLastGDEntry);
4315 AssertRC(rc);
4316 vmdkStreamClearGT(pImage, pExtent);
4317 for (uint32_t i = uLastGDEntry + 1; i < pExtent->cGDEntries; i++)
4318 {
4319 rc = vmdkStreamFlushGT(pImage, pExtent, i);
4320 AssertRC(rc);
4321 }
4322
4323 uint64_t uFileOffset = pExtent->uAppendPosition;
4324 if (!uFileOffset)
4325 return VERR_INTERNAL_ERROR;
4326 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4327
4328 /* From now on it's not safe to append any more data. */
4329 pExtent->uAppendPosition = 0;
4330
4331 /* Grain directory marker. */
4332 uint8_t aMarker[512];
4333 PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
4334 memset(pMarker, '\0', sizeof(aMarker));
4335 pMarker->uSector = VMDK_BYTE2SECTOR(RT_ALIGN_64(RT_H2LE_U64(pExtent->cGDEntries * sizeof(uint32_t)), 512));
4336 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GD);
4337 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage, uFileOffset,
4338 aMarker, sizeof(aMarker), NULL);
4339 AssertRC(rc);
4340 uFileOffset += 512;
4341
4342 /* Write grain directory in little endian style. The array will
4343 * not be used after this, so convert in place. */
4344 uint32_t *pGDTmp = pExtent->pGD;
4345 for (uint32_t i = 0; i < pExtent->cGDEntries; i++, pGDTmp++)
4346 *pGDTmp = RT_H2LE_U32(*pGDTmp);
4347 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4348 uFileOffset, pExtent->pGD,
4349 pExtent->cGDEntries * sizeof(uint32_t),
4350 NULL);
4351 AssertRC(rc);
4352
4353 pExtent->uSectorGD = VMDK_BYTE2SECTOR(uFileOffset);
4354 pExtent->uSectorRGD = VMDK_BYTE2SECTOR(uFileOffset);
4355 uFileOffset = RT_ALIGN_64( uFileOffset
4356 + pExtent->cGDEntries * sizeof(uint32_t),
4357 512);
4358
4359 /* Footer marker. */
4360 memset(pMarker, '\0', sizeof(aMarker));
4361 pMarker->uSector = VMDK_BYTE2SECTOR(512);
4362 pMarker->uType = RT_H2LE_U32(VMDK_MARKER_FOOTER);
4363 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4364 uFileOffset, aMarker, sizeof(aMarker), NULL);
4365 AssertRC(rc);
4366
4367 uFileOffset += 512;
4368 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
4369 AssertRC(rc);
4370
4371 uFileOffset += 512;
4372 /* End-of-stream marker. */
4373 memset(pMarker, '\0', sizeof(aMarker));
4374 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4375 uFileOffset, aMarker, sizeof(aMarker), NULL);
4376 AssertRC(rc);
4377 }
4378 }
4379 else
4380 vmdkFlushImage(pImage);
4381
4382 if (pImage->pExtents != NULL)
4383 {
4384 for (unsigned i = 0 ; i < pImage->cExtents; i++)
4385 vmdkFreeExtentData(pImage, &pImage->pExtents[i], fDelete);
4386 RTMemFree(pImage->pExtents);
4387 pImage->pExtents = NULL;
4388 }
4389 pImage->cExtents = 0;
4390 if (pImage->pFile != NULL)
4391 vmdkFileClose(pImage, &pImage->pFile, fDelete);
4392 vmdkFileCheckAllClose(pImage);
4393
4394 if (pImage->pGTCache)
4395 {
4396 RTMemFree(pImage->pGTCache);
4397 pImage->pGTCache = NULL;
4398 }
4399 if (pImage->pDescData)
4400 {
4401 RTMemFree(pImage->pDescData);
4402 pImage->pDescData = NULL;
4403 }
4404 }
4405
4406 LogFlowFunc(("returns %Rrc\n", rc));
4407 return rc;
4408}
4409
4410/**
4411 * Internal. Flush image data (and metadata) to disk.
4412 */
4413static int vmdkFlushImage(PVMDKIMAGE pImage)
4414{
4415 PVMDKEXTENT pExtent;
4416 int rc = VINF_SUCCESS;
4417
4418 /* Update descriptor if changed. */
4419 if (pImage->Descriptor.fDirty)
4420 {
4421 rc = vmdkWriteDescriptor(pImage);
4422 if (RT_FAILURE(rc))
4423 goto out;
4424 }
4425
4426 for (unsigned i = 0; i < pImage->cExtents; i++)
4427 {
4428 pExtent = &pImage->pExtents[i];
4429 if (pExtent->pFile != NULL && pExtent->fMetaDirty)
4430 {
4431 switch (pExtent->enmType)
4432 {
4433 case VMDKETYPE_HOSTED_SPARSE:
4434 if (!pExtent->fFooter)
4435 {
4436 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, 0);
4437 if (RT_FAILURE(rc))
4438 goto out;
4439 }
4440 else
4441 {
4442 uint64_t uFileOffset = pExtent->uAppendPosition;
4443 /* Simply skip writing anything if the streamOptimized
4444 * image hasn't been just created. */
4445 if (!uFileOffset)
4446 break;
4447 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4448 rc = vmdkWriteMetaSparseExtent(pImage, pExtent,
4449 uFileOffset);
4450 if (RT_FAILURE(rc))
4451 goto out;
4452 }
4453 break;
4454#ifdef VBOX_WITH_VMDK_ESX
4455 case VMDKETYPE_ESX_SPARSE:
4456 /** @todo update the header. */
4457 break;
4458#endif /* VBOX_WITH_VMDK_ESX */
4459 case VMDKETYPE_VMFS:
4460 case VMDKETYPE_FLAT:
4461 /* Nothing to do. */
4462 break;
4463 case VMDKETYPE_ZERO:
4464 default:
4465 AssertMsgFailed(("extent with type %d marked as dirty\n",
4466 pExtent->enmType));
4467 break;
4468 }
4469 }
4470 switch (pExtent->enmType)
4471 {
4472 case VMDKETYPE_HOSTED_SPARSE:
4473#ifdef VBOX_WITH_VMDK_ESX
4474 case VMDKETYPE_ESX_SPARSE:
4475#endif /* VBOX_WITH_VMDK_ESX */
4476 case VMDKETYPE_VMFS:
4477 case VMDKETYPE_FLAT:
4478 /** @todo implement proper path absolute check. */
4479 if ( pExtent->pFile != NULL
4480 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
4481 && !(pExtent->pszBasename[0] == RTPATH_SLASH))
4482 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pExtent->pFile->pStorage);
4483 break;
4484 case VMDKETYPE_ZERO:
4485 /* No need to do anything for this extent. */
4486 break;
4487 default:
4488 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
4489 break;
4490 }
4491 }
4492
4493out:
4494 return rc;
4495}
4496
4497/**
4498 * Internal. Find extent corresponding to the sector number in the disk.
4499 */
4500static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector,
4501 PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
4502{
4503 PVMDKEXTENT pExtent = NULL;
4504 int rc = VINF_SUCCESS;
4505
4506 for (unsigned i = 0; i < pImage->cExtents; i++)
4507 {
4508 if (offSector < pImage->pExtents[i].cNominalSectors)
4509 {
4510 pExtent = &pImage->pExtents[i];
4511 *puSectorInExtent = offSector + pImage->pExtents[i].uSectorOffset;
4512 break;
4513 }
4514 offSector -= pImage->pExtents[i].cNominalSectors;
4515 }
4516
4517 if (pExtent)
4518 *ppExtent = pExtent;
4519 else
4520 rc = VERR_IO_SECTOR_NOT_FOUND;
4521
4522 return rc;
4523}
4524
4525/**
4526 * Internal. Hash function for placing the grain table hash entries.
4527 */
4528static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector,
4529 unsigned uExtent)
4530{
4531 /** @todo this hash function is quite simple, maybe use a better one which
4532 * scrambles the bits better. */
4533 return (uSector + uExtent) % pCache->cEntries;
4534}
4535
4536/**
4537 * Internal. Get sector number in the extent file from the relative sector
4538 * number in the extent.
4539 */
4540static int vmdkGetSector(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4541 uint64_t uSector, uint64_t *puExtentSector)
4542{
4543 PVMDKGTCACHE pCache = pImage->pGTCache;
4544 uint64_t uGDIndex, uGTSector, uGTBlock;
4545 uint32_t uGTHash, uGTBlockIndex;
4546 PVMDKGTCACHEENTRY pGTCacheEntry;
4547 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
4548 int rc;
4549
4550 /* For newly created and readonly/sequentially opened streamOptimized
4551 * images this must be a no-op, as the grain directory is not there. */
4552 if ( ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
4553 && pExtent->uAppendPosition)
4554 || ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
4555 && pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY
4556 && pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
4557 {
4558 *puExtentSector = 0;
4559 return VINF_SUCCESS;
4560 }
4561
4562 uGDIndex = uSector / pExtent->cSectorsPerGDE;
4563 if (uGDIndex >= pExtent->cGDEntries)
4564 return VERR_OUT_OF_RANGE;
4565 uGTSector = pExtent->pGD[uGDIndex];
4566 if (!uGTSector)
4567 {
4568 /* There is no grain table referenced by this grain directory
4569 * entry. So there is absolutely no data in this area. */
4570 *puExtentSector = 0;
4571 return VINF_SUCCESS;
4572 }
4573
4574 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
4575 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
4576 pGTCacheEntry = &pCache->aGTCache[uGTHash];
4577 if ( pGTCacheEntry->uExtent != pExtent->uExtent
4578 || pGTCacheEntry->uGTBlock != uGTBlock)
4579 {
4580 /* Cache miss, fetch data from disk. */
4581 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
4582 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
4583 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4584 if (RT_FAILURE(rc))
4585 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
4586 pGTCacheEntry->uExtent = pExtent->uExtent;
4587 pGTCacheEntry->uGTBlock = uGTBlock;
4588 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
4589 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
4590 }
4591 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
4592 uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
4593 if (uGrainSector)
4594 *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
4595 else
4596 *puExtentSector = 0;
4597 return VINF_SUCCESS;
4598}
4599
4600/**
4601 * Internal. Get sector number in the extent file from the relative sector
4602 * number in the extent - version for async access.
4603 */
4604static int vmdkGetSectorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx,
4605 PVMDKEXTENT pExtent, uint64_t uSector,
4606 uint64_t *puExtentSector)
4607{
4608 PVMDKGTCACHE pCache = pImage->pGTCache;
4609 uint64_t uGDIndex, uGTSector, uGTBlock;
4610 uint32_t uGTHash, uGTBlockIndex;
4611 PVMDKGTCACHEENTRY pGTCacheEntry;
4612 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
4613 int rc;
4614
4615 uGDIndex = uSector / pExtent->cSectorsPerGDE;
4616 if (uGDIndex >= pExtent->cGDEntries)
4617 return VERR_OUT_OF_RANGE;
4618 uGTSector = pExtent->pGD[uGDIndex];
4619 if (!uGTSector)
4620 {
4621 /* There is no grain table referenced by this grain directory
4622 * entry. So there is absolutely no data in this area. */
4623 *puExtentSector = 0;
4624 return VINF_SUCCESS;
4625 }
4626
4627 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
4628 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
4629 pGTCacheEntry = &pCache->aGTCache[uGTHash];
4630 if ( pGTCacheEntry->uExtent != pExtent->uExtent
4631 || pGTCacheEntry->uGTBlock != uGTBlock)
4632 {
4633 /* Cache miss, fetch data from disk. */
4634 PVDMETAXFER pMetaXfer;
4635 rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
4636 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
4637 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer, NULL, NULL);
4638 if (RT_FAILURE(rc))
4639 return rc;
4640 /* We can release the metadata transfer immediately. */
4641 vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer);
4642 pGTCacheEntry->uExtent = pExtent->uExtent;
4643 pGTCacheEntry->uGTBlock = uGTBlock;
4644 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
4645 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
4646 }
4647 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
4648 uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
4649 if (uGrainSector)
4650 *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
4651 else
4652 *puExtentSector = 0;
4653 return VINF_SUCCESS;
4654}
4655
4656/**
4657 * Internal. Allocates a new grain table (if necessary), writes the grain
4658 * and updates the grain table. The cache is also updated by this operation.
4659 * This is separate from vmdkGetSector, because that should be as fast as
4660 * possible. Most code from vmdkGetSector also appears here.
4661 */
4662static int vmdkAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4663 uint64_t uSector, const void *pvBuf,
4664 uint64_t cbWrite)
4665{
4666 PVMDKGTCACHE pCache = pImage->pGTCache;
4667 uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
4668 uint64_t uFileOffset;
4669 uint32_t uGTHash, uGTBlockIndex;
4670 PVMDKGTCACHEENTRY pGTCacheEntry;
4671 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
4672 int rc;
4673
4674 uGDIndex = uSector / pExtent->cSectorsPerGDE;
4675 if (uGDIndex >= pExtent->cGDEntries)
4676 return VERR_OUT_OF_RANGE;
4677 uGTSector = pExtent->pGD[uGDIndex];
4678 if (pExtent->pRGD)
4679 uRGTSector = pExtent->pRGD[uGDIndex];
4680 else
4681 uRGTSector = 0; /**< avoid compiler warning */
4682 if (!uGTSector)
4683 {
4684 /* There is no grain table referenced by this grain directory
4685 * entry. So there is absolutely no data in this area. Allocate
4686 * a new grain table and put the reference to it in the GDs. */
4687 uFileOffset = pExtent->uAppendPosition;
4688 if (!uFileOffset)
4689 return VERR_INTERNAL_ERROR;
4690 Assert(!(uFileOffset % 512));
4691 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4692 uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
4693
4694 pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
4695
4696 /* Normally the grain table is preallocated for hosted sparse extents
4697 * that support more than 32 bit sector numbers. So this shouldn't
4698 * ever happen on a valid extent. */
4699 if (uGTSector > UINT32_MAX)
4700 return VERR_VD_VMDK_INVALID_HEADER;
4701
4702 /* Write grain table by writing the required number of grain table
4703 * cache chunks. Avoids dynamic memory allocation, but is a bit
4704 * slower. But as this is a pretty infrequently occurring case it
4705 * should be acceptable. */
4706 memset(aGTDataTmp, '\0', sizeof(aGTDataTmp));
4707 for (unsigned i = 0;
4708 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
4709 i++)
4710 {
4711 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4712 VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
4713 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4714 if (RT_FAILURE(rc))
4715 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
4716 }
4717 pExtent->uAppendPosition = RT_ALIGN_64( pExtent->uAppendPosition
4718 + pExtent->cGTEntries * sizeof(uint32_t),
4719 512);
4720
4721 if (pExtent->pRGD)
4722 {
4723 AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
4724 uFileOffset = pExtent->uAppendPosition;
4725 if (!uFileOffset)
4726 return VERR_INTERNAL_ERROR;
4727 Assert(!(uFileOffset % 512));
4728 uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
4729
4730 pExtent->uAppendPosition += pExtent->cGTEntries * sizeof(uint32_t);
4731
4732 /* Normally the redundant grain table is preallocated for hosted
4733 * sparse extents that support more than 32 bit sector numbers. So
4734 * this shouldn't ever happen on a valid extent. */
4735 if (uRGTSector > UINT32_MAX)
4736 return VERR_VD_VMDK_INVALID_HEADER;
4737
4738 /* Write backup grain table by writing the required number of grain
4739 * table cache chunks. Avoids dynamic memory allocation, but is a
4740 * bit slower. But as this is a pretty infrequently occurring case
4741 * it should be acceptable. */
4742 for (unsigned i = 0;
4743 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
4744 i++)
4745 {
4746 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4747 VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
4748 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4749 if (RT_FAILURE(rc))
4750 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
4751 }
4752
4753 pExtent->uAppendPosition = pExtent->uAppendPosition
4754 + pExtent->cGTEntries * sizeof(uint32_t);
4755 }
4756
4757 /* Update the grain directory on disk (doing it before writing the
4758 * grain table will result in a garbled extent if the operation is
4759 * aborted for some reason. Otherwise the worst that can happen is
4760 * some unused sectors in the extent. */
4761 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
4762 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4763 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
4764 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
4765 if (RT_FAILURE(rc))
4766 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
4767 if (pExtent->pRGD)
4768 {
4769 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
4770 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4771 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
4772 &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
4773 if (RT_FAILURE(rc))
4774 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
4775 }
4776
4777 /* As the final step update the in-memory copy of the GDs. */
4778 pExtent->pGD[uGDIndex] = uGTSector;
4779 if (pExtent->pRGD)
4780 pExtent->pRGD[uGDIndex] = uRGTSector;
4781 }
4782
4783 uFileOffset = pExtent->uAppendPosition;
4784 if (!uFileOffset)
4785 return VERR_INTERNAL_ERROR;
4786 Assert(!(uFileOffset % 512));
4787
4788 /* Write the data. Always a full grain, or we're in big trouble. */
4789 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
4790 {
4791 if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
4792 return vdIfError(pImage->pIfError, VERR_INTERNAL_ERROR, RT_SRC_POS, N_("VMDK: not enough data for a compressed data block in '%s'"), pExtent->pszFullname);
4793
4794 /* Invalidate cache, just in case some code incorrectly allows mixing
4795 * of reads and writes. Normally shouldn't be needed. */
4796 pExtent->uGrainSectorAbs = 0;
4797
4798 /* Write compressed data block and the markers. */
4799 uint32_t cbGrain = 0;
4800 rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset,
4801 pvBuf, cbWrite, uSector, &cbGrain);
4802 if (RT_FAILURE(rc))
4803 {
4804 AssertRC(rc);
4805 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated compressed data block in '%s'"), pExtent->pszFullname);
4806 }
4807 pExtent->uLastGrainAccess = uSector / pExtent->cSectorsPerGrain;
4808 pExtent->uAppendPosition += cbGrain;
4809 }
4810 else
4811 {
4812 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4813 uFileOffset, pvBuf, cbWrite, NULL);
4814 if (RT_FAILURE(rc))
4815 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
4816 pExtent->uAppendPosition += cbWrite;
4817 }
4818
4819 /* Update the grain table (and the cache). */
4820 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
4821 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
4822 pGTCacheEntry = &pCache->aGTCache[uGTHash];
4823 if ( pGTCacheEntry->uExtent != pExtent->uExtent
4824 || pGTCacheEntry->uGTBlock != uGTBlock)
4825 {
4826 /* Cache miss, fetch data from disk. */
4827 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
4828 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
4829 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4830 if (RT_FAILURE(rc))
4831 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
4832 pGTCacheEntry->uExtent = pExtent->uExtent;
4833 pGTCacheEntry->uGTBlock = uGTBlock;
4834 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
4835 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
4836 }
4837 else
4838 {
4839 /* Cache hit. Convert grain table block back to disk format, otherwise
4840 * the code below will write garbage for all but the updated entry. */
4841 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
4842 aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
4843 }
4844 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
4845 aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(uFileOffset));
4846 pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(uFileOffset);
4847 /* Update grain table on disk. */
4848 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4849 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
4850 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4851 if (RT_FAILURE(rc))
4852 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
4853 if (pExtent->pRGD)
4854 {
4855 /* Update backup grain table on disk. */
4856 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
4857 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
4858 aGTDataTmp, sizeof(aGTDataTmp), NULL);
4859 if (RT_FAILURE(rc))
4860 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
4861 }
4862#ifdef VBOX_WITH_VMDK_ESX
4863 if (RT_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
4864 {
4865 pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
4866 pExtent->fMetaDirty = true;
4867 }
4868#endif /* VBOX_WITH_VMDK_ESX */
4869 return rc;
4870}
4871
4872/**
4873 * Internal. Writes the grain and also if necessary the grain tables.
4874 * Uses the grain table cache as a true grain table.
4875 */
4876static int vmdkStreamAllocGrain(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4877 uint64_t uSector, const void *pvBuf,
4878 uint64_t cbWrite)
4879{
4880 uint32_t uGrain;
4881 uint32_t uGDEntry, uLastGDEntry;
4882 uint32_t cbGrain = 0;
4883 uint32_t uCacheLine, uCacheEntry;
4884 const void *pData = pvBuf;
4885 int rc;
4886
4887 /* Very strict requirements: always write at least one full grain, with
4888 * proper alignment. Everything else would require reading of already
4889 * written data, which we don't support for obvious reasons. The only
4890 * exception is the last grain, and only if the image size specifies
4891 * that only some portion holds data. In any case the write must be
4892 * within the image limits, no "overshoot" allowed. */
4893 if ( cbWrite == 0
4894 || ( cbWrite < VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
4895 && pExtent->cNominalSectors - uSector >= pExtent->cSectorsPerGrain)
4896 || uSector % pExtent->cSectorsPerGrain
4897 || uSector + VMDK_BYTE2SECTOR(cbWrite) > pExtent->cNominalSectors)
4898 return VERR_INVALID_PARAMETER;
4899
4900 /* Clip write range to at most the rest of the grain. */
4901 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSector % pExtent->cSectorsPerGrain));
4902
4903 /* Do not allow to go back. */
4904 uGrain = uSector / pExtent->cSectorsPerGrain;
4905 uCacheLine = uGrain % pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
4906 uCacheEntry = uGrain % VMDK_GT_CACHELINE_SIZE;
4907 uGDEntry = uGrain / pExtent->cGTEntries;
4908 uLastGDEntry = pExtent->uLastGrainAccess / pExtent->cGTEntries;
4909 if (uGrain < pExtent->uLastGrainAccess)
4910 return VERR_VD_VMDK_INVALID_WRITE;
4911
4912 /* Zero byte write optimization. Since we don't tell VBoxHDD that we need
4913 * to allocate something, we also need to detect the situation ourself. */
4914 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
4915 && ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbWrite * 8) == -1)
4916 return VINF_SUCCESS;
4917
4918 if (uGDEntry != uLastGDEntry)
4919 {
4920 rc = vmdkStreamFlushGT(pImage, pExtent, uLastGDEntry);
4921 if (RT_FAILURE(rc))
4922 return rc;
4923 vmdkStreamClearGT(pImage, pExtent);
4924 for (uint32_t i = uLastGDEntry + 1; i < uGDEntry; i++)
4925 {
4926 rc = vmdkStreamFlushGT(pImage, pExtent, i);
4927 if (RT_FAILURE(rc))
4928 return rc;
4929 }
4930 }
4931
4932 uint64_t uFileOffset;
4933 uFileOffset = pExtent->uAppendPosition;
4934 if (!uFileOffset)
4935 return VERR_INTERNAL_ERROR;
4936 /* Align to sector, as the previous write could have been any size. */
4937 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
4938
4939 /* Paranoia check: extent type, grain table buffer presence and
4940 * grain table buffer space. Also grain table entry must be clear. */
4941 if ( pExtent->enmType != VMDKETYPE_HOSTED_SPARSE
4942 || !pImage->pGTCache
4943 || pExtent->cGTEntries > VMDK_GT_CACHE_SIZE * VMDK_GT_CACHELINE_SIZE
4944 || pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry])
4945 return VERR_INTERNAL_ERROR;
4946
4947 /* Update grain table entry. */
4948 pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry] = VMDK_BYTE2SECTOR(uFileOffset);
4949
4950 if (cbWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
4951 {
4952 memcpy(pExtent->pvGrain, pvBuf, cbWrite);
4953 memset((char *)pExtent->pvGrain + cbWrite, '\0',
4954 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite);
4955 pData = pExtent->pvGrain;
4956 }
4957 rc = vmdkFileDeflateSync(pImage, pExtent, uFileOffset, pData,
4958 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
4959 uSector, &cbGrain);
4960 if (RT_FAILURE(rc))
4961 {
4962 pExtent->uGrainSectorAbs = 0;
4963 AssertRC(rc);
4964 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname);
4965 }
4966 pExtent->uLastGrainAccess = uGrain;
4967 pExtent->uAppendPosition += cbGrain;
4968
4969 return rc;
4970}
4971
4972/**
4973 * Internal: Updates the grain table during a async grain allocation.
4974 */
4975static int vmdkAllocGrainAsyncGTUpdate(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
4976 PVDIOCTX pIoCtx,
4977 PVMDKGRAINALLOCASYNC pGrainAlloc)
4978{
4979 int rc = VINF_SUCCESS;
4980 PVMDKGTCACHE pCache = pImage->pGTCache;
4981 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
4982 uint32_t uGTHash, uGTBlockIndex;
4983 uint64_t uGTSector, uRGTSector, uGTBlock;
4984 uint64_t uSector = pGrainAlloc->uSector;
4985 PVMDKGTCACHEENTRY pGTCacheEntry;
4986
4987 LogFlowFunc(("pImage=%#p pExtent=%#p pCache=%#p pIoCtx=%#p pGrainAlloc=%#p\n",
4988 pImage, pExtent, pCache, pIoCtx, pGrainAlloc));
4989
4990 uGTSector = pGrainAlloc->uGTSector;
4991 uRGTSector = pGrainAlloc->uRGTSector;
4992 LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
4993
4994 /* Update the grain table (and the cache). */
4995 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
4996 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
4997 pGTCacheEntry = &pCache->aGTCache[uGTHash];
4998 if ( pGTCacheEntry->uExtent != pExtent->uExtent
4999 || pGTCacheEntry->uGTBlock != uGTBlock)
5000 {
5001 /* Cache miss, fetch data from disk. */
5002 LogFlow(("Cache miss, fetch data from disk\n"));
5003 PVDMETAXFER pMetaXfer = NULL;
5004 rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5005 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5006 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
5007 &pMetaXfer, vmdkAllocGrainAsyncComplete, pGrainAlloc);
5008 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5009 {
5010 pGrainAlloc->cIoXfersPending++;
5011 pGrainAlloc->fGTUpdateNeeded = true;
5012 /* Leave early, we will be called again after the read completed. */
5013 LogFlowFunc(("Metadata read in progress, leaving\n"));
5014 return rc;
5015 }
5016 else if (RT_FAILURE(rc))
5017 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
5018 vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer);
5019 pGTCacheEntry->uExtent = pExtent->uExtent;
5020 pGTCacheEntry->uGTBlock = uGTBlock;
5021 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
5022 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
5023 }
5024 else
5025 {
5026 /* Cache hit. Convert grain table block back to disk format, otherwise
5027 * the code below will write garbage for all but the updated entry. */
5028 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
5029 aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
5030 }
5031 pGrainAlloc->fGTUpdateNeeded = false;
5032 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
5033 aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(pGrainAlloc->uGrainOffset));
5034 pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(pGrainAlloc->uGrainOffset);
5035 /* Update grain table on disk. */
5036 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5037 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5038 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
5039 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5040 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5041 pGrainAlloc->cIoXfersPending++;
5042 else if (RT_FAILURE(rc))
5043 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
5044 if (pExtent->pRGD)
5045 {
5046 /* Update backup grain table on disk. */
5047 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5048 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
5049 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
5050 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5051 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5052 pGrainAlloc->cIoXfersPending++;
5053 else if (RT_FAILURE(rc))
5054 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
5055 }
5056#ifdef VBOX_WITH_VMDK_ESX
5057 if (RT_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
5058 {
5059 pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
5060 pExtent->fMetaDirty = true;
5061 }
5062#endif /* VBOX_WITH_VMDK_ESX */
5063
5064 LogFlowFunc(("leaving rc=%Rrc\n", rc));
5065
5066 return rc;
5067}
5068
5069/**
5070 * Internal - complete the grain allocation by updating disk grain table if required.
5071 */
5072static int vmdkAllocGrainAsyncComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
5073{
5074 int rc = VINF_SUCCESS;
5075 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
5076 PVMDKGRAINALLOCASYNC pGrainAlloc = (PVMDKGRAINALLOCASYNC)pvUser;
5077 PVMDKEXTENT pExtent = pGrainAlloc->pExtent;
5078
5079 LogFlowFunc(("pBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc\n",
5080 pBackendData, pIoCtx, pvUser, rcReq));
5081
5082 pGrainAlloc->cIoXfersPending--;
5083 if (!pGrainAlloc->cIoXfersPending && pGrainAlloc->fGTUpdateNeeded)
5084 rc = vmdkAllocGrainAsyncGTUpdate(pImage, pGrainAlloc->pExtent,
5085 pIoCtx, pGrainAlloc);
5086
5087 if (!pGrainAlloc->cIoXfersPending)
5088 {
5089 /* Grain allocation completed. */
5090 RTMemFree(pGrainAlloc);
5091 }
5092
5093 LogFlowFunc(("Leaving rc=%Rrc\n", rc));
5094 return rc;
5095}
5096
5097/**
5098 * Internal. Allocates a new grain table (if necessary) - async version.
5099 */
5100static int vmdkAllocGrainAsync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
5101 PVDIOCTX pIoCtx, uint64_t uSector,
5102 uint64_t cbWrite)
5103{
5104 PVMDKGTCACHE pCache = pImage->pGTCache;
5105 uint64_t uGDIndex, uGTSector, uRGTSector;
5106 uint64_t uFileOffset;
5107 PVMDKGRAINALLOCASYNC pGrainAlloc = NULL;
5108 int rc;
5109
5110 LogFlowFunc(("pCache=%#p pExtent=%#p pIoCtx=%#p uSector=%llu cbWrite=%llu\n",
5111 pCache, pExtent, pIoCtx, uSector, cbWrite));
5112
5113 AssertReturn(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), VERR_NOT_SUPPORTED);
5114
5115 pGrainAlloc = (PVMDKGRAINALLOCASYNC)RTMemAllocZ(sizeof(VMDKGRAINALLOCASYNC));
5116 if (!pGrainAlloc)
5117 return VERR_NO_MEMORY;
5118
5119 pGrainAlloc->pExtent = pExtent;
5120 pGrainAlloc->uSector = uSector;
5121
5122 uGDIndex = uSector / pExtent->cSectorsPerGDE;
5123 if (uGDIndex >= pExtent->cGDEntries)
5124 {
5125 RTMemFree(pGrainAlloc);
5126 return VERR_OUT_OF_RANGE;
5127 }
5128 uGTSector = pExtent->pGD[uGDIndex];
5129 if (pExtent->pRGD)
5130 uRGTSector = pExtent->pRGD[uGDIndex];
5131 else
5132 uRGTSector = 0; /**< avoid compiler warning */
5133 if (!uGTSector)
5134 {
5135 LogFlow(("Allocating new grain table\n"));
5136
5137 /* There is no grain table referenced by this grain directory
5138 * entry. So there is absolutely no data in this area. Allocate
5139 * a new grain table and put the reference to it in the GDs. */
5140 uFileOffset = pExtent->uAppendPosition;
5141 if (!uFileOffset)
5142 return VERR_INTERNAL_ERROR;
5143 Assert(!(uFileOffset % 512));
5144
5145 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
5146 uGTSector = VMDK_BYTE2SECTOR(uFileOffset);
5147
5148 /* Normally the grain table is preallocated for hosted sparse extents
5149 * that support more than 32 bit sector numbers. So this shouldn't
5150 * ever happen on a valid extent. */
5151 if (uGTSector > UINT32_MAX)
5152 return VERR_VD_VMDK_INVALID_HEADER;
5153
5154 /* Write grain table by writing the required number of grain table
5155 * cache chunks. Allocate memory dynamically here or we flood the
5156 * metadata cache with very small entries. */
5157 size_t cbGTDataTmp = pExtent->cGTEntries * sizeof(uint32_t);
5158 uint32_t *paGTDataTmp = (uint32_t *)RTMemTmpAllocZ(cbGTDataTmp);
5159
5160 if (!paGTDataTmp)
5161 return VERR_NO_MEMORY;
5162
5163 memset(paGTDataTmp, '\0', cbGTDataTmp);
5164 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5165 VMDK_SECTOR2BYTE(uGTSector),
5166 paGTDataTmp, cbGTDataTmp, pIoCtx,
5167 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5168 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5169 pGrainAlloc->cIoXfersPending++;
5170 else if (RT_FAILURE(rc))
5171 {
5172 RTMemTmpFree(paGTDataTmp);
5173 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
5174 }
5175 pExtent->uAppendPosition = RT_ALIGN_64( pExtent->uAppendPosition
5176 + cbGTDataTmp, 512);
5177
5178 if (pExtent->pRGD)
5179 {
5180 AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
5181 uFileOffset = pExtent->uAppendPosition;
5182 if (!uFileOffset)
5183 return VERR_INTERNAL_ERROR;
5184 Assert(!(uFileOffset % 512));
5185 uRGTSector = VMDK_BYTE2SECTOR(uFileOffset);
5186
5187 /* Normally the redundant grain table is preallocated for hosted
5188 * sparse extents that support more than 32 bit sector numbers. So
5189 * this shouldn't ever happen on a valid extent. */
5190 if (uRGTSector > UINT32_MAX)
5191 {
5192 RTMemTmpFree(paGTDataTmp);
5193 return VERR_VD_VMDK_INVALID_HEADER;
5194 }
5195
5196 /* Write grain table by writing the required number of grain table
5197 * cache chunks. Allocate memory dynamically here or we flood the
5198 * metadata cache with very small entries. */
5199 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5200 VMDK_SECTOR2BYTE(uRGTSector),
5201 paGTDataTmp, cbGTDataTmp, pIoCtx,
5202 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5203 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5204 pGrainAlloc->cIoXfersPending++;
5205 else if (RT_FAILURE(rc))
5206 {
5207 RTMemTmpFree(paGTDataTmp);
5208 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
5209 }
5210
5211 pExtent->uAppendPosition = pExtent->uAppendPosition + cbGTDataTmp;
5212 }
5213
5214 RTMemTmpFree(paGTDataTmp);
5215
5216 /* Update the grain directory on disk (doing it before writing the
5217 * grain table will result in a garbled extent if the operation is
5218 * aborted for some reason. Otherwise the worst that can happen is
5219 * some unused sectors in the extent. */
5220 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
5221 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5222 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
5223 &uGTSectorLE, sizeof(uGTSectorLE), pIoCtx,
5224 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5225 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5226 pGrainAlloc->cIoXfersPending++;
5227 else if (RT_FAILURE(rc))
5228 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
5229 if (pExtent->pRGD)
5230 {
5231 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
5232 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5233 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uGTSectorLE),
5234 &uRGTSectorLE, sizeof(uRGTSectorLE), pIoCtx,
5235 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5236 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5237 pGrainAlloc->cIoXfersPending++;
5238 else if (RT_FAILURE(rc))
5239 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
5240 }
5241
5242 /* As the final step update the in-memory copy of the GDs. */
5243 pExtent->pGD[uGDIndex] = uGTSector;
5244 if (pExtent->pRGD)
5245 pExtent->pRGD[uGDIndex] = uRGTSector;
5246 }
5247
5248 LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
5249 pGrainAlloc->uGTSector = uGTSector;
5250 pGrainAlloc->uRGTSector = uRGTSector;
5251
5252 uFileOffset = pExtent->uAppendPosition;
5253 if (!uFileOffset)
5254 return VERR_INTERNAL_ERROR;
5255 Assert(!(uFileOffset % 512));
5256
5257 pGrainAlloc->uGrainOffset = uFileOffset;
5258
5259 /* Write the data. Always a full grain, or we're in big trouble. */
5260 rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pExtent->pFile->pStorage,
5261 uFileOffset, pIoCtx, cbWrite,
5262 vmdkAllocGrainAsyncComplete, pGrainAlloc);
5263 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
5264 pGrainAlloc->cIoXfersPending++;
5265 else if (RT_FAILURE(rc))
5266 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
5267
5268 pExtent->uAppendPosition += cbWrite;
5269
5270 rc = vmdkAllocGrainAsyncGTUpdate(pImage, pExtent, pIoCtx, pGrainAlloc);
5271
5272 if (!pGrainAlloc->cIoXfersPending)
5273 {
5274 /* Grain allocation completed. */
5275 RTMemFree(pGrainAlloc);
5276 }
5277
5278 LogFlowFunc(("leaving rc=%Rrc\n", rc));
5279
5280 return rc;
5281}
5282
5283/**
5284 * Internal. Reads the contents by sequentially going over the compressed
5285 * grains (hoping that they are in sequence).
5286 */
5287static int vmdkStreamReadSequential(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
5288 uint64_t uSector, void *pvBuf,
5289 uint64_t cbRead)
5290{
5291 int rc;
5292
5293 /* Do not allow to go back. */
5294 uint32_t uGrain = uSector / pExtent->cSectorsPerGrain;
5295 if (uGrain < pExtent->uLastGrainAccess)
5296 return VERR_VD_VMDK_INVALID_STATE;
5297 pExtent->uLastGrainAccess = uGrain;
5298
5299 /* After a previous error do not attempt to recover, as it would need
5300 * seeking (in the general case backwards which is forbidden). */
5301 if (!pExtent->uGrainSectorAbs)
5302 return VERR_VD_VMDK_INVALID_STATE;
5303
5304 /* Check if we need to read something from the image or if what we have
5305 * in the buffer is good to fulfill the request. */
5306 if (!pExtent->cbGrainStreamRead || uGrain > pExtent->uGrain)
5307 {
5308 uint32_t uGrainSectorAbs = pExtent->uGrainSectorAbs
5309 + VMDK_BYTE2SECTOR(pExtent->cbGrainStreamRead);
5310
5311 /* Get the marker from the next data block - and skip everything which
5312 * is not a compressed grain. If it's a compressed grain which is for
5313 * the requested sector (or after), read it. */
5314 VMDKMARKER Marker;
5315 do
5316 {
5317 RT_ZERO(Marker);
5318 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
5319 VMDK_SECTOR2BYTE(uGrainSectorAbs),
5320 &Marker, RT_OFFSETOF(VMDKMARKER, uType),
5321 NULL);
5322 if (RT_FAILURE(rc))
5323 return rc;
5324 Marker.uSector = RT_LE2H_U64(Marker.uSector);
5325 Marker.cbSize = RT_LE2H_U32(Marker.cbSize);
5326
5327 if (Marker.cbSize == 0)
5328 {
5329 /* A marker for something else than a compressed grain. */
5330 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
5331 VMDK_SECTOR2BYTE(uGrainSectorAbs)
5332 + RT_OFFSETOF(VMDKMARKER, uType),
5333 &Marker.uType, sizeof(Marker.uType),
5334 NULL);
5335 if (RT_FAILURE(rc))
5336 return rc;
5337 Marker.uType = RT_LE2H_U32(Marker.uType);
5338 switch (Marker.uType)
5339 {
5340 case VMDK_MARKER_EOS:
5341 uGrainSectorAbs++;
5342 /* Read (or mostly skip) to the end of file. Uses the
5343 * Marker (LBA sector) as it is unused anyway. This
5344 * makes sure that really everything is read in the
5345 * success case. If this read fails it means the image
5346 * is truncated, but this is harmless so ignore. */
5347 vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
5348 VMDK_SECTOR2BYTE(uGrainSectorAbs)
5349 + 511,
5350 &Marker.uSector, 1, NULL);
5351 break;
5352 case VMDK_MARKER_GT:
5353 uGrainSectorAbs += 1 + VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
5354 break;
5355 case VMDK_MARKER_GD:
5356 uGrainSectorAbs += 1 + VMDK_BYTE2SECTOR(RT_ALIGN(pExtent->cGDEntries * sizeof(uint32_t), 512));
5357 break;
5358 case VMDK_MARKER_FOOTER:
5359 uGrainSectorAbs += 2;
5360 break;
5361 default:
5362 AssertMsgFailed(("VMDK: corrupted marker, type=%#x\n", Marker.uType));
5363 pExtent->uGrainSectorAbs = 0;
5364 return VERR_VD_VMDK_INVALID_STATE;
5365 }
5366 pExtent->cbGrainStreamRead = 0;
5367 }
5368 else
5369 {
5370 /* A compressed grain marker. If it is at/after what we're
5371 * interested in read and decompress data. */
5372 if (uSector > Marker.uSector + pExtent->cSectorsPerGrain)
5373 {
5374 uGrainSectorAbs += VMDK_BYTE2SECTOR(RT_ALIGN(Marker.cbSize + RT_OFFSETOF(VMDKMARKER, uType), 512));
5375 continue;
5376 }
5377 uint64_t uLBA = 0;
5378 uint32_t cbGrainStreamRead = 0;
5379 rc = vmdkFileInflateSync(pImage, pExtent,
5380 VMDK_SECTOR2BYTE(uGrainSectorAbs),
5381 pExtent->pvGrain,
5382 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
5383 &Marker, &uLBA, &cbGrainStreamRead);
5384 if (RT_FAILURE(rc))
5385 {
5386 pExtent->uGrainSectorAbs = 0;
5387 return rc;
5388 }
5389 if ( pExtent->uGrain
5390 && uLBA / pExtent->cSectorsPerGrain <= pExtent->uGrain)
5391 {
5392 pExtent->uGrainSectorAbs = 0;
5393 return VERR_VD_VMDK_INVALID_STATE;
5394 }
5395 pExtent->uGrain = uLBA / pExtent->cSectorsPerGrain;
5396 pExtent->cbGrainStreamRead = cbGrainStreamRead;
5397 break;
5398 }
5399 } while (Marker.uType != VMDK_MARKER_EOS);
5400
5401 pExtent->uGrainSectorAbs = uGrainSectorAbs;
5402
5403 if (!pExtent->cbGrainStreamRead && Marker.uType == VMDK_MARKER_EOS)
5404 {
5405 pExtent->uGrain = UINT32_MAX;
5406 /* Must set a non-zero value for pExtent->cbGrainStreamRead or
5407 * the next read would try to get more data, and we're at EOF. */
5408 pExtent->cbGrainStreamRead = 1;
5409 }
5410 }
5411
5412 if (pExtent->uGrain > uSector / pExtent->cSectorsPerGrain)
5413 {
5414 /* The next data block we have is not for this area, so just return
5415 * that there is no data. */
5416 return VERR_VD_BLOCK_FREE;
5417 }
5418
5419 uint32_t uSectorInGrain = uSector % pExtent->cSectorsPerGrain;
5420 memcpy(pvBuf,
5421 (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain),
5422 cbRead);
5423 return VINF_SUCCESS;
5424}
5425
5426/**
5427 * Replaces a fragment of a string with the specified string.
5428 *
5429 * @returns Pointer to the allocated UTF-8 string.
5430 * @param pszWhere UTF-8 string to search in.
5431 * @param pszWhat UTF-8 string to search for.
5432 * @param pszByWhat UTF-8 string to replace the found string with.
5433 */
5434static char *vmdkStrReplace(const char *pszWhere, const char *pszWhat,
5435 const char *pszByWhat)
5436{
5437 AssertPtr(pszWhere);
5438 AssertPtr(pszWhat);
5439 AssertPtr(pszByWhat);
5440 const char *pszFoundStr = strstr(pszWhere, pszWhat);
5441 if (!pszFoundStr)
5442 return NULL;
5443 size_t cFinal = strlen(pszWhere) + 1 + strlen(pszByWhat) - strlen(pszWhat);
5444 char *pszNewStr = (char *)RTMemAlloc(cFinal);
5445 if (pszNewStr)
5446 {
5447 char *pszTmp = pszNewStr;
5448 memcpy(pszTmp, pszWhere, pszFoundStr - pszWhere);
5449 pszTmp += pszFoundStr - pszWhere;
5450 memcpy(pszTmp, pszByWhat, strlen(pszByWhat));
5451 pszTmp += strlen(pszByWhat);
5452 strcpy(pszTmp, pszFoundStr + strlen(pszWhat));
5453 }
5454 return pszNewStr;
5455}
5456
5457
5458/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
5459static int vmdkCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
5460 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
5461{
5462 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p penmType=%#p\n",
5463 pszFilename, pVDIfsDisk, pVDIfsImage, penmType));
5464 int rc = VINF_SUCCESS;
5465 PVMDKIMAGE pImage;
5466
5467 if ( !pszFilename
5468 || !*pszFilename
5469 || strchr(pszFilename, '"'))
5470 {
5471 rc = VERR_INVALID_PARAMETER;
5472 goto out;
5473 }
5474
5475 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
5476 if (!pImage)
5477 {
5478 rc = VERR_NO_MEMORY;
5479 goto out;
5480 }
5481 pImage->pszFilename = pszFilename;
5482 pImage->pFile = NULL;
5483 pImage->pExtents = NULL;
5484 pImage->pFiles = NULL;
5485 pImage->pGTCache = NULL;
5486 pImage->pDescData = NULL;
5487 pImage->pVDIfsDisk = pVDIfsDisk;
5488 pImage->pVDIfsImage = pVDIfsImage;
5489 /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
5490 * much as possible in vmdkOpenImage. */
5491 rc = vmdkOpenImage(pImage, VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY);
5492 vmdkFreeImage(pImage, false);
5493 RTMemFree(pImage);
5494
5495 if (RT_SUCCESS(rc))
5496 *penmType = VDTYPE_HDD;
5497
5498out:
5499 LogFlowFunc(("returns %Rrc\n", rc));
5500 return rc;
5501}
5502
5503/** @copydoc VBOXHDDBACKEND::pfnOpen */
5504static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
5505 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
5506 VDTYPE enmType, void **ppBackendData)
5507{
5508 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
5509 int rc;
5510 PVMDKIMAGE pImage;
5511
5512 /* Check open flags. All valid flags are supported. */
5513 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
5514 {
5515 rc = VERR_INVALID_PARAMETER;
5516 goto out;
5517 }
5518
5519 /* Check remaining arguments. */
5520 if ( !VALID_PTR(pszFilename)
5521 || !*pszFilename
5522 || strchr(pszFilename, '"'))
5523 {
5524 rc = VERR_INVALID_PARAMETER;
5525 goto out;
5526 }
5527
5528 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
5529 if (!pImage)
5530 {
5531 rc = VERR_NO_MEMORY;
5532 goto out;
5533 }
5534 pImage->pszFilename = pszFilename;
5535 pImage->pFile = NULL;
5536 pImage->pExtents = NULL;
5537 pImage->pFiles = NULL;
5538 pImage->pGTCache = NULL;
5539 pImage->pDescData = NULL;
5540 pImage->pVDIfsDisk = pVDIfsDisk;
5541 pImage->pVDIfsImage = pVDIfsImage;
5542
5543 rc = vmdkOpenImage(pImage, uOpenFlags);
5544 if (RT_SUCCESS(rc))
5545 *ppBackendData = pImage;
5546
5547out:
5548 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
5549 return rc;
5550}
5551
5552/** @copydoc VBOXHDDBACKEND::pfnCreate */
5553static int vmdkCreate(const char *pszFilename, uint64_t cbSize,
5554 unsigned uImageFlags, const char *pszComment,
5555 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
5556 PCRTUUID pUuid, unsigned uOpenFlags,
5557 unsigned uPercentStart, unsigned uPercentSpan,
5558 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
5559 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
5560{
5561 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));
5562 int rc;
5563 PVMDKIMAGE pImage;
5564
5565 PFNVDPROGRESS pfnProgress = NULL;
5566 void *pvUser = NULL;
5567 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
5568 if (pIfProgress)
5569 {
5570 pfnProgress = pIfProgress->pfnProgress;
5571 pvUser = pIfProgress->Core.pvUser;
5572 }
5573
5574 /* Check the image flags. */
5575 if ((uImageFlags & ~VD_VMDK_IMAGE_FLAGS_MASK) != 0)
5576 {
5577 rc = VERR_VD_INVALID_TYPE;
5578 goto out;
5579 }
5580
5581 /* Check open flags. All valid flags are supported. */
5582 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
5583 {
5584 rc = VERR_INVALID_PARAMETER;
5585 goto out;
5586 }
5587
5588 /* Check size. Maximum 2TB-64K for sparse images, otherwise unlimited. */
5589 if ( !cbSize
5590 || (!(uImageFlags & VD_IMAGE_FLAGS_FIXED) && cbSize >= _1T * 2 - _64K))
5591 {
5592 rc = VERR_VD_INVALID_SIZE;
5593 goto out;
5594 }
5595
5596 /* Check remaining arguments. */
5597 if ( !VALID_PTR(pszFilename)
5598 || !*pszFilename
5599 || strchr(pszFilename, '"')
5600 || !VALID_PTR(pPCHSGeometry)
5601 || !VALID_PTR(pLCHSGeometry)
5602#ifndef VBOX_WITH_VMDK_ESX
5603 || ( uImageFlags & VD_VMDK_IMAGE_FLAGS_ESX
5604 && !(uImageFlags & VD_IMAGE_FLAGS_FIXED))
5605#endif
5606 || ( (uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
5607 && (uImageFlags & ~(VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED | VD_IMAGE_FLAGS_DIFF))))
5608 {
5609 rc = VERR_INVALID_PARAMETER;
5610 goto out;
5611 }
5612
5613 pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
5614 if (!pImage)
5615 {
5616 rc = VERR_NO_MEMORY;
5617 goto out;
5618 }
5619 pImage->pszFilename = pszFilename;
5620 pImage->pFile = NULL;
5621 pImage->pExtents = NULL;
5622 pImage->pFiles = NULL;
5623 pImage->pGTCache = NULL;
5624 pImage->pDescData = NULL;
5625 pImage->pVDIfsDisk = pVDIfsDisk;
5626 pImage->pVDIfsImage = pVDIfsImage;
5627 /* Descriptors for split images can be pretty large, especially if the
5628 * filename is long. So prepare for the worst, and allocate quite some
5629 * memory for the descriptor in this case. */
5630 if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
5631 pImage->cbDescAlloc = VMDK_SECTOR2BYTE(200);
5632 else
5633 pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
5634 pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
5635 if (!pImage->pDescData)
5636 {
5637 RTMemFree(pImage);
5638 rc = VERR_NO_MEMORY;
5639 goto out;
5640 }
5641
5642 rc = vmdkCreateImage(pImage, cbSize, uImageFlags, pszComment,
5643 pPCHSGeometry, pLCHSGeometry, pUuid,
5644 pfnProgress, pvUser, uPercentStart, uPercentSpan);
5645 if (RT_SUCCESS(rc))
5646 {
5647 /* So far the image is opened in read/write mode. Make sure the
5648 * image is opened in read-only mode if the caller requested that. */
5649 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
5650 {
5651 vmdkFreeImage(pImage, false);
5652 rc = vmdkOpenImage(pImage, uOpenFlags);
5653 if (RT_FAILURE(rc))
5654 goto out;
5655 }
5656 *ppBackendData = pImage;
5657 }
5658 else
5659 {
5660 RTMemFree(pImage->pDescData);
5661 RTMemFree(pImage);
5662 }
5663
5664out:
5665 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
5666 return rc;
5667}
5668
5669/** @copydoc VBOXHDDBACKEND::pfnRename */
5670static int vmdkRename(void *pBackendData, const char *pszFilename)
5671{
5672 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
5673
5674 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
5675 int rc = VINF_SUCCESS;
5676 char **apszOldName = NULL;
5677 char **apszNewName = NULL;
5678 char **apszNewLines = NULL;
5679 char *pszOldDescName = NULL;
5680 bool fImageFreed = false;
5681 bool fEmbeddedDesc = false;
5682 unsigned cExtents = 0;
5683 char *pszNewBaseName = NULL;
5684 char *pszOldBaseName = NULL;
5685 char *pszNewFullName = NULL;
5686 char *pszOldFullName = NULL;
5687 const char *pszOldImageName;
5688 unsigned i, line;
5689 VMDKDESCRIPTOR DescriptorCopy;
5690 VMDKEXTENT ExtentCopy;
5691
5692 memset(&DescriptorCopy, 0, sizeof(DescriptorCopy));
5693
5694 /* Check arguments. */
5695 if ( !pImage
5696 || (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK)
5697 || !VALID_PTR(pszFilename)
5698 || !*pszFilename)
5699 {
5700 rc = VERR_INVALID_PARAMETER;
5701 goto out;
5702 }
5703
5704 cExtents = pImage->cExtents;
5705
5706 /*
5707 * Allocate an array to store both old and new names of renamed files
5708 * in case we have to roll back the changes. Arrays are initialized
5709 * with zeros. We actually save stuff when and if we change it.
5710 */
5711 apszOldName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
5712 apszNewName = (char **)RTMemTmpAllocZ((cExtents + 1) * sizeof(char*));
5713 apszNewLines = (char **)RTMemTmpAllocZ((cExtents) * sizeof(char*));
5714 if (!apszOldName || !apszNewName || !apszNewLines)
5715 {
5716 rc = VERR_NO_MEMORY;
5717 goto out;
5718 }
5719
5720 /* Save the descriptor size and position. */
5721 if (pImage->pDescData)
5722 {
5723 /* Separate descriptor file. */
5724 fEmbeddedDesc = false;
5725 }
5726 else
5727 {
5728 /* Embedded descriptor file. */
5729 ExtentCopy = pImage->pExtents[0];
5730 fEmbeddedDesc = true;
5731 }
5732 /* Save the descriptor content. */
5733 DescriptorCopy.cLines = pImage->Descriptor.cLines;
5734 for (i = 0; i < DescriptorCopy.cLines; i++)
5735 {
5736 DescriptorCopy.aLines[i] = RTStrDup(pImage->Descriptor.aLines[i]);
5737 if (!DescriptorCopy.aLines[i])
5738 {
5739 rc = VERR_NO_MEMORY;
5740 goto out;
5741 }
5742 }
5743
5744 /* Prepare both old and new base names used for string replacement. */
5745 pszNewBaseName = RTStrDup(RTPathFilename(pszFilename));
5746 RTPathStripExt(pszNewBaseName);
5747 pszOldBaseName = RTStrDup(RTPathFilename(pImage->pszFilename));
5748 RTPathStripExt(pszOldBaseName);
5749 /* Prepare both old and new full names used for string replacement. */
5750 pszNewFullName = RTStrDup(pszFilename);
5751 RTPathStripExt(pszNewFullName);
5752 pszOldFullName = RTStrDup(pImage->pszFilename);
5753 RTPathStripExt(pszOldFullName);
5754
5755 /* --- Up to this point we have not done any damage yet. --- */
5756
5757 /* Save the old name for easy access to the old descriptor file. */
5758 pszOldDescName = RTStrDup(pImage->pszFilename);
5759 /* Save old image name. */
5760 pszOldImageName = pImage->pszFilename;
5761
5762 /* Update the descriptor with modified extent names. */
5763 for (i = 0, line = pImage->Descriptor.uFirstExtent;
5764 i < cExtents;
5765 i++, line = pImage->Descriptor.aNextLines[line])
5766 {
5767 /* Assume that vmdkStrReplace will fail. */
5768 rc = VERR_NO_MEMORY;
5769 /* Update the descriptor. */
5770 apszNewLines[i] = vmdkStrReplace(pImage->Descriptor.aLines[line],
5771 pszOldBaseName, pszNewBaseName);
5772 if (!apszNewLines[i])
5773 goto rollback;
5774 pImage->Descriptor.aLines[line] = apszNewLines[i];
5775 }
5776 /* Make sure the descriptor gets written back. */
5777 pImage->Descriptor.fDirty = true;
5778 /* Flush the descriptor now, in case it is embedded. */
5779 vmdkFlushImage(pImage);
5780
5781 /* Close and rename/move extents. */
5782 for (i = 0; i < cExtents; i++)
5783 {
5784 PVMDKEXTENT pExtent = &pImage->pExtents[i];
5785 /* Compose new name for the extent. */
5786 apszNewName[i] = vmdkStrReplace(pExtent->pszFullname,
5787 pszOldFullName, pszNewFullName);
5788 if (!apszNewName[i])
5789 goto rollback;
5790 /* Close the extent file. */
5791 vmdkFileClose(pImage, &pExtent->pFile, false);
5792 /* Rename the extent file. */
5793 rc = vdIfIoIntFileMove(pImage->pIfIo, pExtent->pszFullname, apszNewName[i], 0);
5794 if (RT_FAILURE(rc))
5795 goto rollback;
5796 /* Remember the old name. */
5797 apszOldName[i] = RTStrDup(pExtent->pszFullname);
5798 }
5799 /* Release all old stuff. */
5800 vmdkFreeImage(pImage, false);
5801
5802 fImageFreed = true;
5803
5804 /* Last elements of new/old name arrays are intended for
5805 * storing descriptor's names.
5806 */
5807 apszNewName[cExtents] = RTStrDup(pszFilename);
5808 /* Rename the descriptor file if it's separate. */
5809 if (!fEmbeddedDesc)
5810 {
5811 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, apszNewName[cExtents], 0);
5812 if (RT_FAILURE(rc))
5813 goto rollback;
5814 /* Save old name only if we may need to change it back. */
5815 apszOldName[cExtents] = RTStrDup(pszFilename);
5816 }
5817
5818 /* Update pImage with the new information. */
5819 pImage->pszFilename = pszFilename;
5820
5821 /* Open the new image. */
5822 rc = vmdkOpenImage(pImage, pImage->uOpenFlags);
5823 if (RT_SUCCESS(rc))
5824 goto out;
5825
5826rollback:
5827 /* Roll back all changes in case of failure. */
5828 if (RT_FAILURE(rc))
5829 {
5830 int rrc;
5831 if (!fImageFreed)
5832 {
5833 /*
5834 * Some extents may have been closed, close the rest. We will
5835 * re-open the whole thing later.
5836 */
5837 vmdkFreeImage(pImage, false);
5838 }
5839 /* Rename files back. */
5840 for (i = 0; i <= cExtents; i++)
5841 {
5842 if (apszOldName[i])
5843 {
5844 rrc = vdIfIoIntFileMove(pImage->pIfIo, apszNewName[i], apszOldName[i], 0);
5845 AssertRC(rrc);
5846 }
5847 }
5848 /* Restore the old descriptor. */
5849 PVMDKFILE pFile;
5850 rrc = vmdkFileOpen(pImage, &pFile, pszOldDescName,
5851 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_NORMAL,
5852 false /* fCreate */),
5853 false /* fAsyncIO */);
5854 AssertRC(rrc);
5855 if (fEmbeddedDesc)
5856 {
5857 ExtentCopy.pFile = pFile;
5858 pImage->pExtents = &ExtentCopy;
5859 }
5860 else
5861 {
5862 /* Shouldn't be null for separate descriptor.
5863 * There will be no access to the actual content.
5864 */
5865 pImage->pDescData = pszOldDescName;
5866 pImage->pFile = pFile;
5867 }
5868 pImage->Descriptor = DescriptorCopy;
5869 vmdkWriteDescriptor(pImage);
5870 vmdkFileClose(pImage, &pFile, false);
5871 /* Get rid of the stuff we implanted. */
5872 pImage->pExtents = NULL;
5873 pImage->pFile = NULL;
5874 pImage->pDescData = NULL;
5875 /* Re-open the image back. */
5876 pImage->pszFilename = pszOldImageName;
5877 rrc = vmdkOpenImage(pImage, pImage->uOpenFlags);
5878 AssertRC(rrc);
5879 }
5880
5881out:
5882 for (i = 0; i < DescriptorCopy.cLines; i++)
5883 if (DescriptorCopy.aLines[i])
5884 RTStrFree(DescriptorCopy.aLines[i]);
5885 if (apszOldName)
5886 {
5887 for (i = 0; i <= cExtents; i++)
5888 if (apszOldName[i])
5889 RTStrFree(apszOldName[i]);
5890 RTMemTmpFree(apszOldName);
5891 }
5892 if (apszNewName)
5893 {
5894 for (i = 0; i <= cExtents; i++)
5895 if (apszNewName[i])
5896 RTStrFree(apszNewName[i]);
5897 RTMemTmpFree(apszNewName);
5898 }
5899 if (apszNewLines)
5900 {
5901 for (i = 0; i < cExtents; i++)
5902 if (apszNewLines[i])
5903 RTStrFree(apszNewLines[i]);
5904 RTMemTmpFree(apszNewLines);
5905 }
5906 if (pszOldDescName)
5907 RTStrFree(pszOldDescName);
5908 if (pszOldBaseName)
5909 RTStrFree(pszOldBaseName);
5910 if (pszNewBaseName)
5911 RTStrFree(pszNewBaseName);
5912 if (pszOldFullName)
5913 RTStrFree(pszOldFullName);
5914 if (pszNewFullName)
5915 RTStrFree(pszNewFullName);
5916 LogFlowFunc(("returns %Rrc\n", rc));
5917 return rc;
5918}
5919
5920/** @copydoc VBOXHDDBACKEND::pfnClose */
5921static int vmdkClose(void *pBackendData, bool fDelete)
5922{
5923 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
5924 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
5925 int rc;
5926
5927 rc = vmdkFreeImage(pImage, fDelete);
5928 RTMemFree(pImage);
5929
5930 LogFlowFunc(("returns %Rrc\n", rc));
5931 return rc;
5932}
5933
5934/** @copydoc VBOXHDDBACKEND::pfnRead */
5935static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
5936 size_t cbToRead, size_t *pcbActuallyRead)
5937{
5938 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
5939 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
5940 PVMDKEXTENT pExtent;
5941 uint64_t uSectorExtentRel;
5942 uint64_t uSectorExtentAbs;
5943 int rc;
5944
5945 AssertPtr(pImage);
5946 Assert(uOffset % 512 == 0);
5947 Assert(cbToRead % 512 == 0);
5948
5949 if ( uOffset + cbToRead > pImage->cbSize
5950 || cbToRead == 0)
5951 {
5952 rc = VERR_INVALID_PARAMETER;
5953 goto out;
5954 }
5955
5956 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
5957 &pExtent, &uSectorExtentRel);
5958 if (RT_FAILURE(rc))
5959 goto out;
5960
5961 /* Check access permissions as defined in the extent descriptor. */
5962 if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
5963 {
5964 rc = VERR_VD_VMDK_INVALID_STATE;
5965 goto out;
5966 }
5967
5968 /* Clip read range to remain in this extent. */
5969 cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
5970
5971 /* Handle the read according to the current extent type. */
5972 switch (pExtent->enmType)
5973 {
5974 case VMDKETYPE_HOSTED_SPARSE:
5975#ifdef VBOX_WITH_VMDK_ESX
5976 case VMDKETYPE_ESX_SPARSE:
5977#endif /* VBOX_WITH_VMDK_ESX */
5978 rc = vmdkGetSector(pImage, pExtent, uSectorExtentRel,
5979 &uSectorExtentAbs);
5980 if (RT_FAILURE(rc))
5981 goto out;
5982 /* Clip read range to at most the rest of the grain. */
5983 cbToRead = RT_MIN(cbToRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
5984 Assert(!(cbToRead % 512));
5985 if (uSectorExtentAbs == 0)
5986 {
5987 if ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
5988 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
5989 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
5990 rc = VERR_VD_BLOCK_FREE;
5991 else
5992 rc = vmdkStreamReadSequential(pImage, pExtent,
5993 uSectorExtentRel,
5994 pvBuf, cbToRead);
5995 }
5996 else
5997 {
5998 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
5999 {
6000 uint32_t uSectorInGrain = uSectorExtentRel % pExtent->cSectorsPerGrain;
6001 uSectorExtentAbs -= uSectorInGrain;
6002 uint64_t uLBA;
6003 if (pExtent->uGrainSectorAbs != uSectorExtentAbs)
6004 {
6005 rc = vmdkFileInflateSync(pImage, pExtent,
6006 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6007 pExtent->pvGrain,
6008 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
6009 NULL, &uLBA, NULL);
6010 if (RT_FAILURE(rc))
6011 {
6012 pExtent->uGrainSectorAbs = 0;
6013 AssertRC(rc);
6014 goto out;
6015 }
6016 pExtent->uGrainSectorAbs = uSectorExtentAbs;
6017 pExtent->uGrain = uSectorExtentRel / pExtent->cSectorsPerGrain;
6018 Assert(uLBA == uSectorExtentRel);
6019 }
6020 memcpy(pvBuf, (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), cbToRead);
6021 }
6022 else
6023 {
6024 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
6025 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6026 pvBuf, cbToRead, NULL);
6027 }
6028 }
6029 break;
6030 case VMDKETYPE_VMFS:
6031 case VMDKETYPE_FLAT:
6032 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
6033 VMDK_SECTOR2BYTE(uSectorExtentRel),
6034 pvBuf, cbToRead, NULL);
6035 break;
6036 case VMDKETYPE_ZERO:
6037 memset(pvBuf, '\0', cbToRead);
6038 break;
6039 }
6040 if (pcbActuallyRead)
6041 *pcbActuallyRead = cbToRead;
6042
6043out:
6044 LogFlowFunc(("returns %Rrc\n", rc));
6045 return rc;
6046}
6047
6048/** @copydoc VBOXHDDBACKEND::pfnWrite */
6049static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
6050 size_t cbToWrite, size_t *pcbWriteProcess,
6051 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
6052{
6053 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
6054 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6055 PVMDKEXTENT pExtent;
6056 uint64_t uSectorExtentRel;
6057 uint64_t uSectorExtentAbs;
6058 int rc;
6059
6060 AssertPtr(pImage);
6061 Assert(uOffset % 512 == 0);
6062 Assert(cbToWrite % 512 == 0);
6063
6064 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6065 {
6066 rc = VERR_VD_IMAGE_READ_ONLY;
6067 goto out;
6068 }
6069
6070 if (cbToWrite == 0)
6071 {
6072 rc = VERR_INVALID_PARAMETER;
6073 goto out;
6074 }
6075
6076 /* No size check here, will do that later when the extent is located.
6077 * There are sparse images out there which according to the spec are
6078 * invalid, because the total size is not a multiple of the grain size.
6079 * Also for sparse images which are stitched together in odd ways (not at
6080 * grain boundaries, and with the nominal size not being a multiple of the
6081 * grain size), this would prevent writing to the last grain. */
6082
6083 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
6084 &pExtent, &uSectorExtentRel);
6085 if (RT_FAILURE(rc))
6086 goto out;
6087
6088 /* Check access permissions as defined in the extent descriptor. */
6089 if ( pExtent->enmAccess != VMDKACCESS_READWRITE
6090 && ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6091 && !pImage->pExtents[0].uAppendPosition
6092 && pExtent->enmAccess != VMDKACCESS_READONLY))
6093 {
6094 rc = VERR_VD_VMDK_INVALID_STATE;
6095 goto out;
6096 }
6097
6098 /* Handle the write according to the current extent type. */
6099 switch (pExtent->enmType)
6100 {
6101 case VMDKETYPE_HOSTED_SPARSE:
6102#ifdef VBOX_WITH_VMDK_ESX
6103 case VMDKETYPE_ESX_SPARSE:
6104#endif /* VBOX_WITH_VMDK_ESX */
6105 rc = vmdkGetSector(pImage, pExtent, uSectorExtentRel,
6106 &uSectorExtentAbs);
6107 if (RT_FAILURE(rc))
6108 goto out;
6109 /* Clip write range to at most the rest of the grain. */
6110 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
6111 if ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
6112 && uSectorExtentRel < (uint64_t)pExtent->uLastGrainAccess * pExtent->cSectorsPerGrain)
6113 {
6114 rc = VERR_VD_VMDK_INVALID_WRITE;
6115 goto out;
6116 }
6117 if (uSectorExtentAbs == 0)
6118 {
6119 if (!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6120 {
6121 if (cbToWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
6122 {
6123 /* Full block write to a previously unallocated block.
6124 * Check if the caller wants feedback. */
6125 if (!(fWrite & VD_WRITE_NO_ALLOC))
6126 {
6127 /* Allocate GT and store the grain. */
6128 rc = vmdkAllocGrain(pImage, pExtent,
6129 uSectorExtentRel,
6130 pvBuf, cbToWrite);
6131 }
6132 else
6133 rc = VERR_VD_BLOCK_FREE;
6134 *pcbPreRead = 0;
6135 *pcbPostRead = 0;
6136 }
6137 else
6138 {
6139 /* Clip write range to remain in this extent. */
6140 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6141 *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
6142 *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbToWrite - *pcbPreRead;
6143 rc = VERR_VD_BLOCK_FREE;
6144 }
6145 }
6146 else
6147 {
6148 rc = vmdkStreamAllocGrain(pImage, pExtent,
6149 uSectorExtentRel,
6150 pvBuf, cbToWrite);
6151 }
6152 }
6153 else
6154 {
6155 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6156 {
6157 /* A partial write to a streamOptimized image is simply
6158 * invalid. It requires rewriting already compressed data
6159 * which is somewhere between expensive and impossible. */
6160 rc = VERR_VD_VMDK_INVALID_STATE;
6161 pExtent->uGrainSectorAbs = 0;
6162 AssertRC(rc);
6163 }
6164 else
6165 {
6166 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
6167 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6168 pvBuf, cbToWrite, NULL);
6169 }
6170 }
6171 break;
6172 case VMDKETYPE_VMFS:
6173 case VMDKETYPE_FLAT:
6174 /* Clip write range to remain in this extent. */
6175 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6176 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
6177 VMDK_SECTOR2BYTE(uSectorExtentRel),
6178 pvBuf, cbToWrite, NULL);
6179 break;
6180 case VMDKETYPE_ZERO:
6181 /* Clip write range to remain in this extent. */
6182 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6183 break;
6184 }
6185
6186 if (pcbWriteProcess)
6187 *pcbWriteProcess = cbToWrite;
6188
6189out:
6190 LogFlowFunc(("returns %Rrc\n", rc));
6191 return rc;
6192}
6193
6194/** @copydoc VBOXHDDBACKEND::pfnFlush */
6195static int vmdkFlush(void *pBackendData)
6196{
6197 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6198 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6199 int rc = VINF_SUCCESS;
6200
6201 AssertPtr(pImage);
6202
6203 if (!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6204 rc = vmdkFlushImage(pImage);
6205
6206 LogFlowFunc(("returns %Rrc\n", rc));
6207 return rc;
6208}
6209
6210/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
6211static unsigned vmdkGetVersion(void *pBackendData)
6212{
6213 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6214 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6215
6216 AssertPtr(pImage);
6217
6218 if (pImage)
6219 return VMDK_IMAGE_VERSION;
6220 else
6221 return 0;
6222}
6223
6224/** @copydoc VBOXHDDBACKEND::pfnGetSize */
6225static uint64_t vmdkGetSize(void *pBackendData)
6226{
6227 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6228 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6229
6230 AssertPtr(pImage);
6231
6232 if (pImage)
6233 return pImage->cbSize;
6234 else
6235 return 0;
6236}
6237
6238/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
6239static uint64_t vmdkGetFileSize(void *pBackendData)
6240{
6241 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6242 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6243 uint64_t cb = 0;
6244
6245 AssertPtr(pImage);
6246
6247 if (pImage)
6248 {
6249 uint64_t cbFile;
6250 if (pImage->pFile != NULL)
6251 {
6252 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pFile->pStorage, &cbFile);
6253 if (RT_SUCCESS(rc))
6254 cb += cbFile;
6255 }
6256 for (unsigned i = 0; i < pImage->cExtents; i++)
6257 {
6258 if (pImage->pExtents[i].pFile != NULL)
6259 {
6260 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pExtents[i].pFile->pStorage, &cbFile);
6261 if (RT_SUCCESS(rc))
6262 cb += cbFile;
6263 }
6264 }
6265 }
6266
6267 LogFlowFunc(("returns %lld\n", cb));
6268 return cb;
6269}
6270
6271/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
6272static int vmdkGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
6273{
6274 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
6275 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6276 int rc;
6277
6278 AssertPtr(pImage);
6279
6280 if (pImage)
6281 {
6282 if (pImage->PCHSGeometry.cCylinders)
6283 {
6284 *pPCHSGeometry = pImage->PCHSGeometry;
6285 rc = VINF_SUCCESS;
6286 }
6287 else
6288 rc = VERR_VD_GEOMETRY_NOT_SET;
6289 }
6290 else
6291 rc = VERR_VD_NOT_OPENED;
6292
6293 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
6294 return rc;
6295}
6296
6297/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
6298static int vmdkSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
6299{
6300 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
6301 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6302 int rc;
6303
6304 AssertPtr(pImage);
6305
6306 if (pImage)
6307 {
6308 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6309 {
6310 rc = VERR_VD_IMAGE_READ_ONLY;
6311 goto out;
6312 }
6313 if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6314 {
6315 rc = VERR_NOT_SUPPORTED;
6316 goto out;
6317 }
6318 rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
6319 if (RT_FAILURE(rc))
6320 goto out;
6321
6322 pImage->PCHSGeometry = *pPCHSGeometry;
6323 rc = VINF_SUCCESS;
6324 }
6325 else
6326 rc = VERR_VD_NOT_OPENED;
6327
6328out:
6329 LogFlowFunc(("returns %Rrc\n", rc));
6330 return rc;
6331}
6332
6333/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
6334static int vmdkGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
6335{
6336 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
6337 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6338 int rc;
6339
6340 AssertPtr(pImage);
6341
6342 if (pImage)
6343 {
6344 if (pImage->LCHSGeometry.cCylinders)
6345 {
6346 *pLCHSGeometry = pImage->LCHSGeometry;
6347 rc = VINF_SUCCESS;
6348 }
6349 else
6350 rc = VERR_VD_GEOMETRY_NOT_SET;
6351 }
6352 else
6353 rc = VERR_VD_NOT_OPENED;
6354
6355 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
6356 return rc;
6357}
6358
6359/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
6360static int vmdkSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
6361{
6362 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
6363 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6364 int rc;
6365
6366 AssertPtr(pImage);
6367
6368 if (pImage)
6369 {
6370 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6371 {
6372 rc = VERR_VD_IMAGE_READ_ONLY;
6373 goto out;
6374 }
6375 if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6376 {
6377 rc = VERR_NOT_SUPPORTED;
6378 goto out;
6379 }
6380 rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
6381 if (RT_FAILURE(rc))
6382 goto out;
6383
6384 pImage->LCHSGeometry = *pLCHSGeometry;
6385 rc = VINF_SUCCESS;
6386 }
6387 else
6388 rc = VERR_VD_NOT_OPENED;
6389
6390out:
6391 LogFlowFunc(("returns %Rrc\n", rc));
6392 return rc;
6393}
6394
6395/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
6396static unsigned vmdkGetImageFlags(void *pBackendData)
6397{
6398 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6399 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6400 unsigned uImageFlags;
6401
6402 AssertPtr(pImage);
6403
6404 if (pImage)
6405 uImageFlags = pImage->uImageFlags;
6406 else
6407 uImageFlags = 0;
6408
6409 LogFlowFunc(("returns %#x\n", uImageFlags));
6410 return uImageFlags;
6411}
6412
6413/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
6414static unsigned vmdkGetOpenFlags(void *pBackendData)
6415{
6416 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
6417 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6418 unsigned uOpenFlags;
6419
6420 AssertPtr(pImage);
6421
6422 if (pImage)
6423 uOpenFlags = pImage->uOpenFlags;
6424 else
6425 uOpenFlags = 0;
6426
6427 LogFlowFunc(("returns %#x\n", uOpenFlags));
6428 return uOpenFlags;
6429}
6430
6431/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
6432static int vmdkSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
6433{
6434 LogFlowFunc(("pBackendData=%#p uOpenFlags=%#x\n", pBackendData, uOpenFlags));
6435 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6436 int rc;
6437
6438 /* Image must be opened and the new flags must be valid. */
6439 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
6440 {
6441 rc = VERR_INVALID_PARAMETER;
6442 goto out;
6443 }
6444
6445 /* StreamOptimized images need special treatment: reopen is prohibited. */
6446 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6447 {
6448 if (pImage->uOpenFlags == uOpenFlags)
6449 rc = VINF_SUCCESS;
6450 else
6451 rc = VERR_INVALID_PARAMETER;
6452 goto out;
6453 }
6454
6455 /* Implement this operation via reopening the image. */
6456 vmdkFreeImage(pImage, false);
6457 rc = vmdkOpenImage(pImage, uOpenFlags);
6458
6459out:
6460 LogFlowFunc(("returns %Rrc\n", rc));
6461 return rc;
6462}
6463
6464/** @copydoc VBOXHDDBACKEND::pfnGetComment */
6465static int vmdkGetComment(void *pBackendData, char *pszComment,
6466 size_t cbComment)
6467{
6468 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
6469 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6470 int rc;
6471
6472 AssertPtr(pImage);
6473
6474 if (pImage)
6475 {
6476 const char *pszCommentEncoded = NULL;
6477 rc = vmdkDescDDBGetStr(pImage, &pImage->Descriptor,
6478 "ddb.comment", &pszCommentEncoded);
6479 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
6480 pszCommentEncoded = NULL;
6481 else if (RT_FAILURE(rc))
6482 goto out;
6483
6484 if (pszComment && pszCommentEncoded)
6485 rc = vmdkDecodeString(pszCommentEncoded, pszComment, cbComment);
6486 else
6487 {
6488 if (pszComment)
6489 *pszComment = '\0';
6490 rc = VINF_SUCCESS;
6491 }
6492 if (pszCommentEncoded)
6493 RTStrFree((char *)(void *)pszCommentEncoded);
6494 }
6495 else
6496 rc = VERR_VD_NOT_OPENED;
6497
6498out:
6499 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
6500 return rc;
6501}
6502
6503/** @copydoc VBOXHDDBACKEND::pfnSetComment */
6504static int vmdkSetComment(void *pBackendData, const char *pszComment)
6505{
6506 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
6507 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6508 int rc;
6509
6510 AssertPtr(pImage);
6511
6512 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6513 {
6514 rc = VERR_VD_IMAGE_READ_ONLY;
6515 goto out;
6516 }
6517 if (pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
6518 {
6519 rc = VERR_NOT_SUPPORTED;
6520 goto out;
6521 }
6522
6523 if (pImage)
6524 rc = vmdkSetImageComment(pImage, pszComment);
6525 else
6526 rc = VERR_VD_NOT_OPENED;
6527
6528out:
6529 LogFlowFunc(("returns %Rrc\n", rc));
6530 return rc;
6531}
6532
6533/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
6534static int vmdkGetUuid(void *pBackendData, PRTUUID pUuid)
6535{
6536 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6537 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6538 int rc;
6539
6540 AssertPtr(pImage);
6541
6542 if (pImage)
6543 {
6544 *pUuid = pImage->ImageUuid;
6545 rc = VINF_SUCCESS;
6546 }
6547 else
6548 rc = VERR_VD_NOT_OPENED;
6549
6550 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6551 return rc;
6552}
6553
6554/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
6555static int vmdkSetUuid(void *pBackendData, PCRTUUID pUuid)
6556{
6557 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6558 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6559 int rc;
6560
6561 LogFlowFunc(("%RTuuid\n", pUuid));
6562 AssertPtr(pImage);
6563
6564 if (pImage)
6565 {
6566 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6567 {
6568 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6569 {
6570 pImage->ImageUuid = *pUuid;
6571 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
6572 VMDK_DDB_IMAGE_UUID, pUuid);
6573 if (RT_FAILURE(rc))
6574 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
6575 rc = VINF_SUCCESS;
6576 }
6577 else
6578 rc = VERR_NOT_SUPPORTED;
6579 }
6580 else
6581 rc = VERR_VD_IMAGE_READ_ONLY;
6582 }
6583 else
6584 rc = VERR_VD_NOT_OPENED;
6585
6586 LogFlowFunc(("returns %Rrc\n", rc));
6587 return rc;
6588}
6589
6590/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
6591static int vmdkGetModificationUuid(void *pBackendData, PRTUUID pUuid)
6592{
6593 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6594 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6595 int rc;
6596
6597 AssertPtr(pImage);
6598
6599 if (pImage)
6600 {
6601 *pUuid = pImage->ModificationUuid;
6602 rc = VINF_SUCCESS;
6603 }
6604 else
6605 rc = VERR_VD_NOT_OPENED;
6606
6607 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6608 return rc;
6609}
6610
6611/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
6612static int vmdkSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
6613{
6614 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6615 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6616 int rc;
6617
6618 AssertPtr(pImage);
6619
6620 if (pImage)
6621 {
6622 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6623 {
6624 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6625 {
6626 /* Only touch the modification uuid if it changed. */
6627 if (RTUuidCompare(&pImage->ModificationUuid, pUuid))
6628 {
6629 pImage->ModificationUuid = *pUuid;
6630 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
6631 VMDK_DDB_MODIFICATION_UUID, pUuid);
6632 if (RT_FAILURE(rc))
6633 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in descriptor in '%s'"), pImage->pszFilename);
6634 }
6635 rc = VINF_SUCCESS;
6636 }
6637 else
6638 rc = VERR_NOT_SUPPORTED;
6639 }
6640 else
6641 rc = VERR_VD_IMAGE_READ_ONLY;
6642 }
6643 else
6644 rc = VERR_VD_NOT_OPENED;
6645
6646 LogFlowFunc(("returns %Rrc\n", rc));
6647 return rc;
6648}
6649
6650/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
6651static int vmdkGetParentUuid(void *pBackendData, PRTUUID pUuid)
6652{
6653 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6654 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6655 int rc;
6656
6657 AssertPtr(pImage);
6658
6659 if (pImage)
6660 {
6661 *pUuid = pImage->ParentUuid;
6662 rc = VINF_SUCCESS;
6663 }
6664 else
6665 rc = VERR_VD_NOT_OPENED;
6666
6667 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6668 return rc;
6669}
6670
6671/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
6672static int vmdkSetParentUuid(void *pBackendData, PCRTUUID pUuid)
6673{
6674 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6675 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6676 int rc;
6677
6678 AssertPtr(pImage);
6679
6680 if (pImage)
6681 {
6682 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6683 {
6684 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6685 {
6686 pImage->ParentUuid = *pUuid;
6687 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
6688 VMDK_DDB_PARENT_UUID, pUuid);
6689 if (RT_FAILURE(rc))
6690 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
6691 rc = VINF_SUCCESS;
6692 }
6693 else
6694 rc = VERR_NOT_SUPPORTED;
6695 }
6696 else
6697 rc = VERR_VD_IMAGE_READ_ONLY;
6698 }
6699 else
6700 rc = VERR_VD_NOT_OPENED;
6701
6702 LogFlowFunc(("returns %Rrc\n", rc));
6703 return rc;
6704}
6705
6706/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
6707static int vmdkGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
6708{
6709 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
6710 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6711 int rc;
6712
6713 AssertPtr(pImage);
6714
6715 if (pImage)
6716 {
6717 *pUuid = pImage->ParentModificationUuid;
6718 rc = VINF_SUCCESS;
6719 }
6720 else
6721 rc = VERR_VD_NOT_OPENED;
6722
6723 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
6724 return rc;
6725}
6726
6727/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
6728static int vmdkSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
6729{
6730 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
6731 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6732 int rc;
6733
6734 AssertPtr(pImage);
6735
6736 if (pImage)
6737 {
6738 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
6739 {
6740 if (!(pImage->uOpenFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED))
6741 {
6742 pImage->ParentModificationUuid = *pUuid;
6743 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
6744 VMDK_DDB_PARENT_MODIFICATION_UUID, pUuid);
6745 if (RT_FAILURE(rc))
6746 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in descriptor in '%s'"), pImage->pszFilename);
6747 rc = VINF_SUCCESS;
6748 }
6749 else
6750 rc = VERR_NOT_SUPPORTED;
6751 }
6752 else
6753 rc = VERR_VD_IMAGE_READ_ONLY;
6754 }
6755 else
6756 rc = VERR_VD_NOT_OPENED;
6757
6758 LogFlowFunc(("returns %Rrc\n", rc));
6759 return rc;
6760}
6761
6762/** @copydoc VBOXHDDBACKEND::pfnDump */
6763static void vmdkDump(void *pBackendData)
6764{
6765 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6766
6767 AssertPtr(pImage);
6768 if (pImage)
6769 {
6770 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
6771 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
6772 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
6773 VMDK_BYTE2SECTOR(pImage->cbSize));
6774 vdIfErrorMessage(pImage->pIfError, "Header: uuidCreation={%RTuuid}\n", &pImage->ImageUuid);
6775 vdIfErrorMessage(pImage->pIfError, "Header: uuidModification={%RTuuid}\n", &pImage->ModificationUuid);
6776 vdIfErrorMessage(pImage->pIfError, "Header: uuidParent={%RTuuid}\n", &pImage->ParentUuid);
6777 vdIfErrorMessage(pImage->pIfError, "Header: uuidParentModification={%RTuuid}\n", &pImage->ParentModificationUuid);
6778 }
6779}
6780
6781/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
6782static int vmdkAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
6783 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
6784{
6785 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
6786 pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
6787 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6788 PVMDKEXTENT pExtent;
6789 uint64_t uSectorExtentRel;
6790 uint64_t uSectorExtentAbs;
6791 int rc;
6792
6793 AssertPtr(pImage);
6794 Assert(uOffset % 512 == 0);
6795 Assert(cbRead % 512 == 0);
6796
6797 if ( uOffset + cbRead > pImage->cbSize
6798 || cbRead == 0)
6799 {
6800 rc = VERR_INVALID_PARAMETER;
6801 goto out;
6802 }
6803
6804 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
6805 &pExtent, &uSectorExtentRel);
6806 if (RT_FAILURE(rc))
6807 goto out;
6808
6809 /* Check access permissions as defined in the extent descriptor. */
6810 if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
6811 {
6812 rc = VERR_VD_VMDK_INVALID_STATE;
6813 goto out;
6814 }
6815
6816 /* Clip read range to remain in this extent. */
6817 cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6818
6819 /* Handle the read according to the current extent type. */
6820 switch (pExtent->enmType)
6821 {
6822 case VMDKETYPE_HOSTED_SPARSE:
6823#ifdef VBOX_WITH_VMDK_ESX
6824 case VMDKETYPE_ESX_SPARSE:
6825#endif /* VBOX_WITH_VMDK_ESX */
6826 rc = vmdkGetSectorAsync(pImage, pIoCtx, pExtent,
6827 uSectorExtentRel, &uSectorExtentAbs);
6828 if (RT_FAILURE(rc))
6829 goto out;
6830 /* Clip read range to at most the rest of the grain. */
6831 cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
6832 Assert(!(cbRead % 512));
6833 if (uSectorExtentAbs == 0)
6834 rc = VERR_VD_BLOCK_FREE;
6835 else
6836 {
6837 AssertMsg(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), ("Async I/O is not supported for stream optimized VMDK's\n"));
6838 rc = vdIfIoIntFileReadUserAsync(pImage->pIfIo, pExtent->pFile->pStorage,
6839 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6840 pIoCtx, cbRead);
6841 }
6842 break;
6843 case VMDKETYPE_VMFS:
6844 case VMDKETYPE_FLAT:
6845 rc = vdIfIoIntFileReadUserAsync(pImage->pIfIo, pExtent->pFile->pStorage,
6846 VMDK_SECTOR2BYTE(uSectorExtentRel),
6847 pIoCtx, cbRead);
6848 break;
6849 case VMDKETYPE_ZERO:
6850 size_t cbSet;
6851
6852 cbSet = vdIfIoIntIoCtxSet(pImage->pIfIo, pIoCtx, 0, cbRead);
6853 Assert(cbSet == cbRead);
6854
6855 rc = VINF_SUCCESS;
6856 break;
6857 }
6858 if (pcbActuallyRead)
6859 *pcbActuallyRead = cbRead;
6860
6861out:
6862 LogFlowFunc(("returns %Rrc\n", rc));
6863 return rc;
6864}
6865
6866/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
6867static int vmdkAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
6868 PVDIOCTX pIoCtx,
6869 size_t *pcbWriteProcess, size_t *pcbPreRead,
6870 size_t *pcbPostRead, unsigned fWrite)
6871{
6872 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
6873 pBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
6874 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6875 PVMDKEXTENT pExtent;
6876 uint64_t uSectorExtentRel;
6877 uint64_t uSectorExtentAbs;
6878 int rc;
6879
6880 AssertPtr(pImage);
6881 Assert(uOffset % 512 == 0);
6882 Assert(cbWrite % 512 == 0);
6883
6884 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
6885 {
6886 rc = VERR_VD_IMAGE_READ_ONLY;
6887 goto out;
6888 }
6889
6890 if (cbWrite == 0)
6891 {
6892 rc = VERR_INVALID_PARAMETER;
6893 goto out;
6894 }
6895
6896 /* No size check here, will do that later when the extent is located.
6897 * There are sparse images out there which according to the spec are
6898 * invalid, because the total size is not a multiple of the grain size.
6899 * Also for sparse images which are stitched together in odd ways (not at
6900 * grain boundaries, and with the nominal size not being a multiple of the
6901 * grain size), this would prevent writing to the last grain. */
6902
6903 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
6904 &pExtent, &uSectorExtentRel);
6905 if (RT_FAILURE(rc))
6906 goto out;
6907
6908 /* Check access permissions as defined in the extent descriptor. */
6909 if (pExtent->enmAccess != VMDKACCESS_READWRITE)
6910 {
6911 rc = VERR_VD_VMDK_INVALID_STATE;
6912 goto out;
6913 }
6914
6915 /* Handle the write according to the current extent type. */
6916 switch (pExtent->enmType)
6917 {
6918 case VMDKETYPE_HOSTED_SPARSE:
6919#ifdef VBOX_WITH_VMDK_ESX
6920 case VMDKETYPE_ESX_SPARSE:
6921#endif /* VBOX_WITH_VMDK_ESX */
6922 rc = vmdkGetSectorAsync(pImage, pIoCtx, pExtent, uSectorExtentRel,
6923 &uSectorExtentAbs);
6924 if (RT_FAILURE(rc))
6925 goto out;
6926 /* Clip write range to at most the rest of the grain. */
6927 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
6928 if ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
6929 && uSectorExtentRel < (uint64_t)pExtent->uLastGrainAccess * pExtent->cSectorsPerGrain)
6930 {
6931 rc = VERR_VD_VMDK_INVALID_WRITE;
6932 goto out;
6933 }
6934 if (uSectorExtentAbs == 0)
6935 {
6936 if (cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
6937 {
6938 /* Full block write to a previously unallocated block.
6939 * Check if the caller wants to avoid the automatic alloc. */
6940 if (!(fWrite & VD_WRITE_NO_ALLOC))
6941 {
6942 /* Allocate GT and find out where to store the grain. */
6943 rc = vmdkAllocGrainAsync(pImage, pExtent, pIoCtx,
6944 uSectorExtentRel, cbWrite);
6945 }
6946 else
6947 rc = VERR_VD_BLOCK_FREE;
6948 *pcbPreRead = 0;
6949 *pcbPostRead = 0;
6950 }
6951 else
6952 {
6953 /* Clip write range to remain in this extent. */
6954 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6955 *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
6956 *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite - *pcbPreRead;
6957 rc = VERR_VD_BLOCK_FREE;
6958 }
6959 }
6960 else
6961 {
6962 Assert(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED));
6963 rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pExtent->pFile->pStorage,
6964 VMDK_SECTOR2BYTE(uSectorExtentAbs),
6965 pIoCtx, cbWrite, NULL, NULL);
6966 }
6967 break;
6968 case VMDKETYPE_VMFS:
6969 case VMDKETYPE_FLAT:
6970 /* Clip write range to remain in this extent. */
6971 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6972 rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pExtent->pFile->pStorage,
6973 VMDK_SECTOR2BYTE(uSectorExtentRel),
6974 pIoCtx, cbWrite, NULL, NULL);
6975 break;
6976 case VMDKETYPE_ZERO:
6977 /* Clip write range to remain in this extent. */
6978 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
6979 break;
6980 }
6981
6982 if (pcbWriteProcess)
6983 *pcbWriteProcess = cbWrite;
6984
6985out:
6986 LogFlowFunc(("returns %Rrc\n", rc));
6987 return rc;
6988}
6989
6990/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
6991static int vmdkAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
6992{
6993 PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
6994 PVMDKEXTENT pExtent;
6995 int rc = VINF_SUCCESS;
6996
6997 /* Update descriptor if changed. */
6998 /** @todo: The descriptor is never updated because
6999 * it remains unchanged during normal operation (only vmdkRename updates it).
7000 * So this part is actually not tested so far and requires testing as soon
7001 * as the descriptor might change during async I/O.
7002 */
7003 if (pImage->Descriptor.fDirty)
7004 {
7005 rc = vmdkWriteDescriptorAsync(pImage, pIoCtx);
7006 if ( RT_FAILURE(rc)
7007 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
7008 goto out;
7009 }
7010
7011 for (unsigned i = 0; i < pImage->cExtents; i++)
7012 {
7013 pExtent = &pImage->pExtents[i];
7014 if (pExtent->pFile != NULL && pExtent->fMetaDirty)
7015 {
7016 switch (pExtent->enmType)
7017 {
7018 case VMDKETYPE_HOSTED_SPARSE:
7019#ifdef VBOX_WITH_VMDK_ESX
7020 case VMDKETYPE_ESX_SPARSE:
7021#endif /* VBOX_WITH_VMDK_ESX */
7022 rc = vmdkWriteMetaSparseExtentAsync(pImage, pExtent, 0, pIoCtx);
7023 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
7024 goto out;
7025 if (pExtent->fFooter)
7026 {
7027 uint64_t uFileOffset = pExtent->uAppendPosition;
7028 if (!uFileOffset)
7029 {
7030 rc = VERR_INTERNAL_ERROR;
7031 goto out;
7032 }
7033 uFileOffset = RT_ALIGN_64(uFileOffset, 512);
7034 rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
7035 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
7036 goto out;
7037 }
7038 break;
7039 case VMDKETYPE_VMFS:
7040 case VMDKETYPE_FLAT:
7041 /* Nothing to do. */
7042 break;
7043 case VMDKETYPE_ZERO:
7044 default:
7045 AssertMsgFailed(("extent with type %d marked as dirty\n",
7046 pExtent->enmType));
7047 break;
7048 }
7049 }
7050 switch (pExtent->enmType)
7051 {
7052 case VMDKETYPE_HOSTED_SPARSE:
7053#ifdef VBOX_WITH_VMDK_ESX
7054 case VMDKETYPE_ESX_SPARSE:
7055#endif /* VBOX_WITH_VMDK_ESX */
7056 case VMDKETYPE_VMFS:
7057 case VMDKETYPE_FLAT:
7058 /*
7059 * Don't ignore block devices like in the sync case
7060 * (they have an absolute path).
7061 * We might have unwritten data in the writeback cache and
7062 * the async I/O manager will handle these requests properly
7063 * even if the block device doesn't support these requests.
7064 */
7065 if ( pExtent->pFile != NULL
7066 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
7067 rc = vdIfIoIntFileFlushAsync(pImage->pIfIo, pExtent->pFile->pStorage,
7068 pIoCtx, NULL, NULL);
7069 break;
7070 case VMDKETYPE_ZERO:
7071 /* No need to do anything for this extent. */
7072 break;
7073 default:
7074 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
7075 break;
7076 }
7077 }
7078
7079out:
7080 return rc;
7081}
7082
7083
7084VBOXHDDBACKEND g_VmdkBackend =
7085{
7086 /* pszBackendName */
7087 "VMDK",
7088 /* cbSize */
7089 sizeof(VBOXHDDBACKEND),
7090 /* uBackendCaps */
7091 VD_CAP_UUID | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC
7092 | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE | VD_CAP_ASYNC
7093 | VD_CAP_VFS,
7094 /* paFileExtensions */
7095 s_aVmdkFileExtensions,
7096 /* paConfigInfo */
7097 NULL,
7098 /* hPlugin */
7099 NIL_RTLDRMOD,
7100 /* pfnCheckIfValid */
7101 vmdkCheckIfValid,
7102 /* pfnOpen */
7103 vmdkOpen,
7104 /* pfnCreate */
7105 vmdkCreate,
7106 /* pfnRename */
7107 vmdkRename,
7108 /* pfnClose */
7109 vmdkClose,
7110 /* pfnRead */
7111 vmdkRead,
7112 /* pfnWrite */
7113 vmdkWrite,
7114 /* pfnFlush */
7115 vmdkFlush,
7116 /* pfnGetVersion */
7117 vmdkGetVersion,
7118 /* pfnGetSize */
7119 vmdkGetSize,
7120 /* pfnGetFileSize */
7121 vmdkGetFileSize,
7122 /* pfnGetPCHSGeometry */
7123 vmdkGetPCHSGeometry,
7124 /* pfnSetPCHSGeometry */
7125 vmdkSetPCHSGeometry,
7126 /* pfnGetLCHSGeometry */
7127 vmdkGetLCHSGeometry,
7128 /* pfnSetLCHSGeometry */
7129 vmdkSetLCHSGeometry,
7130 /* pfnGetImageFlags */
7131 vmdkGetImageFlags,
7132 /* pfnGetOpenFlags */
7133 vmdkGetOpenFlags,
7134 /* pfnSetOpenFlags */
7135 vmdkSetOpenFlags,
7136 /* pfnGetComment */
7137 vmdkGetComment,
7138 /* pfnSetComment */
7139 vmdkSetComment,
7140 /* pfnGetUuid */
7141 vmdkGetUuid,
7142 /* pfnSetUuid */
7143 vmdkSetUuid,
7144 /* pfnGetModificationUuid */
7145 vmdkGetModificationUuid,
7146 /* pfnSetModificationUuid */
7147 vmdkSetModificationUuid,
7148 /* pfnGetParentUuid */
7149 vmdkGetParentUuid,
7150 /* pfnSetParentUuid */
7151 vmdkSetParentUuid,
7152 /* pfnGetParentModificationUuid */
7153 vmdkGetParentModificationUuid,
7154 /* pfnSetParentModificationUuid */
7155 vmdkSetParentModificationUuid,
7156 /* pfnDump */
7157 vmdkDump,
7158 /* pfnGetTimeStamp */
7159 NULL,
7160 /* pfnGetParentTimeStamp */
7161 NULL,
7162 /* pfnSetParentTimeStamp */
7163 NULL,
7164 /* pfnGetParentFilename */
7165 NULL,
7166 /* pfnSetParentFilename */
7167 NULL,
7168 /* pfnAsyncRead */
7169 vmdkAsyncRead,
7170 /* pfnAsyncWrite */
7171 vmdkAsyncWrite,
7172 /* pfnAsyncFlush */
7173 vmdkAsyncFlush,
7174 /* pfnComposeLocation */
7175 genericFileComposeLocation,
7176 /* pfnComposeName */
7177 genericFileComposeName,
7178 /* pfnCompact */
7179 NULL,
7180 /* pfnResize */
7181 NULL,
7182 /* pfnDiscard */
7183 NULL
7184};
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