VirtualBox

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

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

VD,VMDK: Enable debug logging for release builds

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