VirtualBox

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

Last change on this file since 24916 was 24916, checked in by vboxsync, 15 years ago

Storage/VMDK: fix buffers for really huge VMDK files split into 2G pieces, includes changelog

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