VirtualBox

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

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

VMDK: Improve error message if a stream optimized image is corrupted

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

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