VirtualBox

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

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

Storage: Add async discard API

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