VirtualBox

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

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

Storage: Endian fix for VMDK stream optimized images

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette