VirtualBox

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

Last change on this file since 99739 was 99739, checked in by vboxsync, 17 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 379.2 KB
RevLine 
[12641]1/* $Id: VMDK.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
[2358]2/** @file
[32536]3 * VMDK disk image, core code.
[2358]4 */
[97839]5
[2358]6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[2358]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[2358]26 */
[87055]27
28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[2358]32#define LOG_GROUP LOG_GROUP_VD_VMDK
[85902]33#include <VBox/log.h> /* before VBox/vd-ifs.h */
[33567]34#include <VBox/vd-plugin.h>
[2358]35#include <VBox/err.h>
[97839]36
[2358]37#include <iprt/assert.h>
38#include <iprt/alloc.h>
[85902]39#include <iprt/base64.h>
40#include <iprt/ctype.h>
41#include <iprt/crc.h>
42#include <iprt/dvm.h>
[2358]43#include <iprt/uuid.h>
44#include <iprt/path.h>
[85902]45#include <iprt/rand.h>
[2358]46#include <iprt/string.h>
[85902]47#include <iprt/sort.h>
[16827]48#include <iprt/zip.h>
[32642]49#include <iprt/asm.h>
[85902]50#ifdef RT_OS_WINDOWS
51# include <iprt/utf16.h>
52# include <iprt/uni.h>
53# include <iprt/uni.h>
54# include <iprt/nt/nt-and-windows.h>
55# include <winioctl.h>
56#endif
[86604]57#ifdef RT_OS_LINUX
58# include <errno.h>
59# include <sys/stat.h>
60# include <iprt/dir.h>
61# include <iprt/symlink.h>
62# include <iprt/linux/sysfs.h>
63#endif
[87002]64#ifdef RT_OS_FREEBSD
65#include <libgeom.h>
66#include <sys/stat.h>
67#include <stdlib.h>
68#endif
[87050]69#ifdef RT_OS_SOLARIS
70#include <sys/dkio.h>
71#include <sys/vtoc.h>
72#include <sys/efi_partition.h>
73#include <unistd.h>
74#include <errno.h>
75#endif
[87209]76#ifdef RT_OS_DARWIN
77# include <sys/stat.h>
78# include <sys/disk.h>
79# include <errno.h>
80/* The following structure and IOCTLs are defined in znu bsd/sys/disk.h but
81 inside KERNEL ifdefs and thus stripped from the SDK edition of the header.
82 While we could try include the header from the Kernel.framework, it's a lot
83 easier to just add the structure and 4 defines here. */
84typedef struct
85{
86 uint64_t offset;
87 uint64_t length;
88 uint8_t reserved0128[12];
89 dev_t dev;
90} dk_physical_extent_t;
91# define DKIOCGETBASE _IOR( 'd', 73, uint64_t)
92# define DKIOCLOCKPHYSICALEXTENTS _IO( 'd', 81)
93# define DKIOCGETPHYSICALEXTENT _IOWR('d', 82, dk_physical_extent_t)
94# define DKIOCUNLOCKPHYSICALEXTENTS _IO( 'd', 83)
95#endif /* RT_OS_DARWIN */
[97839]96
[50988]97#include "VDBackends.h"
[87054]98
99
[57358]100/*********************************************************************************************************************************
101* Constants And Macros, Structures and Typedefs *
102*********************************************************************************************************************************/
[97839]103
[7576]104/** Maximum encoded string size (including NUL) we allow for VMDK images.
105 * Deliberately not set high to avoid running out of descriptor space. */
[7580]106#define VMDK_ENCODED_COMMENT_MAX 1024
[97839]107
[6291]108/** VMDK descriptor DDB entry for PCHS cylinders. */
109#define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders"
[97839]110
[6291]111/** VMDK descriptor DDB entry for PCHS heads. */
112#define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads"
[97839]113
[6291]114/** VMDK descriptor DDB entry for PCHS sectors. */
115#define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors"
[97839]116
[6291]117/** VMDK descriptor DDB entry for LCHS cylinders. */
118#define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders"
[97839]119
[6291]120/** VMDK descriptor DDB entry for LCHS heads. */
121#define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads"
[97839]122
[6291]123/** VMDK descriptor DDB entry for LCHS sectors. */
124#define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors"
[97839]125
[7155]126/** VMDK descriptor DDB entry for image UUID. */
127#define VMDK_DDB_IMAGE_UUID "ddb.uuid.image"
[97839]128
[7155]129/** VMDK descriptor DDB entry for image modification UUID. */
130#define VMDK_DDB_MODIFICATION_UUID "ddb.uuid.modification"
[97839]131
[7155]132/** VMDK descriptor DDB entry for parent image UUID. */
133#define VMDK_DDB_PARENT_UUID "ddb.uuid.parent"
[97839]134
[7155]135/** VMDK descriptor DDB entry for parent image modification UUID. */
136#define VMDK_DDB_PARENT_MODIFICATION_UUID "ddb.uuid.parentmodification"
[97839]137
[16827]138/** No compression for streamOptimized files. */
139#define VMDK_COMPRESSION_NONE 0
[97839]140
[16827]141/** Deflate compression for streamOptimized files. */
142#define VMDK_COMPRESSION_DEFLATE 1
[97839]143
[16827]144/** Marker that the actual GD value is stored in the footer. */
145#define VMDK_GD_AT_END 0xffffffffffffffffULL
[97839]146
[16827]147/** Marker for end-of-stream in streamOptimized images. */
148#define VMDK_MARKER_EOS 0
[97839]149
[16827]150/** Marker for grain table block in streamOptimized images. */
151#define VMDK_MARKER_GT 1
[97839]152
[16827]153/** Marker for grain directory block in streamOptimized images. */
154#define VMDK_MARKER_GD 2
[97839]155
[16827]156/** Marker for footer in streamOptimized images. */
157#define VMDK_MARKER_FOOTER 3
[97839]158
[38819]159/** Marker for unknown purpose in streamOptimized images.
160 * Shows up in very recent images created by vSphere, but only sporadically.
161 * They "forgot" to document that one in the VMDK specification. */
162#define VMDK_MARKER_UNSPECIFIED 4
[97839]163
[16827]164/** Dummy marker for "don't check the marker value". */
165#define VMDK_MARKER_IGNORE 0xffffffffU
[97839]166
[2358]167/**
168 * Magic number for hosted images created by VMware Workstation 4, VMware
[12306]169 * Workstation 5, VMware Server or VMware Player. Not necessarily sparse.
[2358]170 */
171#define VMDK_SPARSE_MAGICNUMBER 0x564d444b /* 'V' 'M' 'D' 'K' */
[97839]172
[96832]173/** VMDK sector size in bytes. */
174#define VMDK_SECTOR_SIZE 512
175/** Max string buffer size for uint64_t with null term */
176#define UINT64_MAX_BUFF_SIZE 21
177/** Grain directory entry size in bytes */
178#define VMDK_GRAIN_DIR_ENTRY_SIZE 4
179/** Grain table size in bytes */
180#define VMDK_GRAIN_TABLE_SIZE 2048
[97839]181
[12306]182/**
183 * VMDK hosted binary extent header. The "Sparse" is a total misnomer, as
184 * this header is also used for monolithic flat images.
185 */
[2358]186#pragma pack(1)
187typedef struct SparseExtentHeader
188{
189 uint32_t magicNumber;
190 uint32_t version;
191 uint32_t flags;
192 uint64_t capacity;
193 uint64_t grainSize;
194 uint64_t descriptorOffset;
195 uint64_t descriptorSize;
196 uint32_t numGTEsPerGT;
197 uint64_t rgdOffset;
198 uint64_t gdOffset;
199 uint64_t overHead;
200 bool uncleanShutdown;
201 char singleEndLineChar;
202 char nonEndLineChar;
203 char doubleEndLineChar1;
204 char doubleEndLineChar2;
[16827]205 uint16_t compressAlgorithm;
206 uint8_t pad[433];
[2358]207} SparseExtentHeader;
208#pragma pack()
[97839]209
[77773]210/** The maximum allowed descriptor size in the extent header in sectors. */
211#define VMDK_SPARSE_DESCRIPTOR_SIZE_MAX UINT64_C(20480) /* 10MB */
[97839]212
[6291]213/** VMDK capacity for a single chunk when 2G splitting is turned on. Should be
214 * divisible by the default grain size (64K) */
215#define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
[97839]216
[16827]217/** VMDK streamOptimized file format marker. The type field may or may not
218 * be actually valid, but there's always data to read there. */
219#pragma pack(1)
220typedef struct VMDKMARKER
221{
222 uint64_t uSector;
223 uint32_t cbSize;
224 uint32_t uType;
[32536]225} VMDKMARKER, *PVMDKMARKER;
[16827]226#pragma pack()
[97839]227
228
[2358]229/** Convert sector number/size to byte offset/size. */
[18327]230#define VMDK_SECTOR2BYTE(u) ((uint64_t)(u) << 9)
[97839]231
[2358]232/** Convert byte offset/size to sector number/size. */
233#define VMDK_BYTE2SECTOR(u) ((u) >> 9)
[97839]234
[2358]235/**
236 * VMDK extent type.
237 */
238typedef enum VMDKETYPE
239{
240 /** Hosted sparse extent. */
241 VMDKETYPE_HOSTED_SPARSE = 1,
242 /** Flat extent. */
243 VMDKETYPE_FLAT,
244 /** Zero extent. */
[18566]245 VMDKETYPE_ZERO,
246 /** VMFS extent, used by ESX. */
247 VMDKETYPE_VMFS
[2358]248} VMDKETYPE, *PVMDKETYPE;
[97839]249
[2358]250/**
251 * VMDK access type for a extent.
252 */
253typedef enum VMDKACCESS
254{
255 /** No access allowed. */
256 VMDKACCESS_NOACCESS = 0,
257 /** Read-only access. */
258 VMDKACCESS_READONLY,
259 /** Read-write access. */
260 VMDKACCESS_READWRITE
261} VMDKACCESS, *PVMDKACCESS;
[97839]262
[10715]263/** Forward declaration for PVMDKIMAGE. */
264typedef struct VMDKIMAGE *PVMDKIMAGE;
[97839]265
[2358]266/**
[10715]267 * Extents files entry. Used for opening a particular file only once.
268 */
269typedef struct VMDKFILE
270{
[85105]271 /** Pointer to file path. Local copy. */
[27808]272 const char *pszFilename;
[85105]273 /** Pointer to base name. Local copy. */
274 const char *pszBasename;
[10715]275 /** File open flags for consistency checking. */
[27808]276 unsigned fOpen;
[32536]277 /** Handle for sync/async file abstraction.*/
[27808]278 PVDIOSTORAGE pStorage;
[10715]279 /** Reference counter. */
[27808]280 unsigned uReferences;
[10715]281 /** Flag whether the file should be deleted on last close. */
[27808]282 bool fDelete;
[32536]283 /** Pointer to the image we belong to (for debugging purposes). */
[27808]284 PVMDKIMAGE pImage;
[10715]285 /** Pointer to next file descriptor. */
286 struct VMDKFILE *pNext;
287 /** Pointer to the previous file descriptor. */
288 struct VMDKFILE *pPrev;
289} VMDKFILE, *PVMDKFILE;
[97839]290
[10715]291/**
[2358]292 * VMDK extent data structure.
293 */
294typedef struct VMDKEXTENT
295{
296 /** File handle. */
[10715]297 PVMDKFILE pFile;
[2358]298 /** Base name of the image extent. */
[2650]299 const char *pszBasename;
[2358]300 /** Full name of the image extent. */
[2650]301 const char *pszFullname;
[2358]302 /** Number of sectors in this extent. */
303 uint64_t cSectors;
304 /** Number of sectors per block (grain in VMDK speak). */
305 uint64_t cSectorsPerGrain;
306 /** Starting sector number of descriptor. */
307 uint64_t uDescriptorSector;
308 /** Size of descriptor in sectors. */
309 uint64_t cDescriptorSectors;
310 /** Starting sector number of grain directory. */
311 uint64_t uSectorGD;
312 /** Starting sector number of redundant grain directory. */
313 uint64_t uSectorRGD;
314 /** Total number of metadata sectors. */
[2650]315 uint64_t cOverheadSectors;
[2358]316 /** Nominal size (i.e. as described by the descriptor) of this extent. */
317 uint64_t cNominalSectors;
318 /** Sector offset (i.e. as described by the descriptor) of this extent. */
319 uint64_t uSectorOffset;
320 /** Number of entries in a grain table. */
321 uint32_t cGTEntries;
322 /** Number of sectors reachable via a grain directory entry. */
323 uint32_t cSectorsPerGDE;
324 /** Number of entries in the grain directory. */
325 uint32_t cGDEntries;
326 /** Pointer to the next free sector. Legacy information. Do not use. */
327 uint32_t uFreeSector;
328 /** Number of this extent in the list of images. */
329 uint32_t uExtent;
330 /** Pointer to the descriptor (NULL if no descriptor in this extent). */
331 char *pDescData;
332 /** Pointer to the grain directory. */
333 uint32_t *pGD;
334 /** Pointer to the redundant grain directory. */
[16827]335 uint32_t *pRGD;
[17775]336 /** VMDK version of this extent. 1=1.0/1.1 */
[16827]337 uint32_t uVersion;
[2358]338 /** Type of this extent. */
339 VMDKETYPE enmType;
340 /** Access to this extent. */
341 VMDKACCESS enmAccess;
342 /** Flag whether this extent is marked as unclean. */
343 bool fUncleanShutdown;
344 /** Flag whether the metadata in the extent header needs to be updated. */
345 bool fMetaDirty;
[18067]346 /** Flag whether there is a footer in this extent. */
347 bool fFooter;
[16827]348 /** Compression type for this extent. */
349 uint16_t uCompression;
[33088]350 /** Append position for writing new grain. Only for sparse extents. */
351 uint64_t uAppendPosition;
[33182]352 /** Last grain which was accessed. Only for streamOptimized extents. */
353 uint32_t uLastGrainAccess;
354 /** Starting sector corresponding to the grain buffer. */
355 uint32_t uGrainSectorAbs;
356 /** Grain number corresponding to the grain buffer. */
357 uint32_t uGrain;
358 /** Actual size of the compressed data, only valid for reading. */
359 uint32_t cbGrainStreamRead;
[32882]360 /** Size of compressed grain buffer for streamOptimized extents. */
361 size_t cbCompGrain;
362 /** Compressed grain buffer for streamOptimized extents, with marker. */
363 void *pvCompGrain;
[16827]364 /** Decompressed grain buffer for streamOptimized extents. */
365 void *pvGrain;
[2358]366 /** Reference to the image in which this extent is used. Do not use this
367 * on a regular basis to avoid passing pImage references to functions
368 * explicitly. */
369 struct VMDKIMAGE *pImage;
370} VMDKEXTENT, *PVMDKEXTENT;
[97839]371
[2358]372/**
373 * Grain table cache size. Allocated per image.
374 */
375#define VMDK_GT_CACHE_SIZE 256
[97839]376
[2358]377/**
378 * Grain table block size. Smaller than an actual grain table block to allow
379 * more grain table blocks to be cached without having to allocate excessive
380 * amounts of memory for the cache.
381 */
382#define VMDK_GT_CACHELINE_SIZE 128
[97839]383
384
[2358]385/**
386 * Maximum number of lines in a descriptor file. Not worth the effort of
[24916]387 * making it variable. Descriptor files are generally very short (~20 lines),
388 * with the exception of sparse files split in 2G chunks, which need for the
389 * maximum size (almost 2T) exactly 1025 lines for the disk database.
[2358]390 */
[24916]391#define VMDK_DESCRIPTOR_LINES_MAX 1100U
[97839]392
[2358]393/**
394 * Parsed descriptor information. Allows easy access and update of the
395 * descriptor (whether separate file or not). Free form text files suck.
396 */
397typedef struct VMDKDESCRIPTOR
398{
399 /** Line number of first entry of the disk descriptor. */
400 unsigned uFirstDesc;
401 /** Line number of first entry in the extent description. */
402 unsigned uFirstExtent;
403 /** Line number of first disk database entry. */
404 unsigned uFirstDDB;
405 /** Total number of lines. */
406 unsigned cLines;
407 /** Total amount of memory available for the descriptor. */
408 size_t cbDescAlloc;
[2650]409 /** Set if descriptor has been changed and not yet written to disk. */
[2358]410 bool fDirty;
411 /** Array of pointers to the data in the descriptor. */
412 char *aLines[VMDK_DESCRIPTOR_LINES_MAX];
413 /** Array of line indices pointing to the next non-comment line. */
414 unsigned aNextLines[VMDK_DESCRIPTOR_LINES_MAX];
415} VMDKDESCRIPTOR, *PVMDKDESCRIPTOR;
[97839]416
417
[2358]418/**
419 * Cache entry for translating extent/sector to a sector number in that
420 * extent.
421 */
422typedef struct VMDKGTCACHEENTRY
423{
424 /** Extent number for which this entry is valid. */
425 uint32_t uExtent;
426 /** GT data block number. */
427 uint64_t uGTBlock;
428 /** Data part of the cache entry. */
429 uint32_t aGTData[VMDK_GT_CACHELINE_SIZE];
430} VMDKGTCACHEENTRY, *PVMDKGTCACHEENTRY;
[97839]431
[2358]432/**
433 * Cache data structure for blocks of grain table entries. For now this is a
434 * fixed size direct mapping cache, but this should be adapted to the size of
435 * the sparse image and maybe converted to a set-associative cache. The
436 * implementation below implements a write-through cache with write allocate.
437 */
438typedef struct VMDKGTCACHE
439{
440 /** Cache entries. */
441 VMDKGTCACHEENTRY aGTCache[VMDK_GT_CACHE_SIZE];
442 /** Number of cache entries (currently unused). */
443 unsigned cEntries;
444} VMDKGTCACHE, *PVMDKGTCACHE;
[97839]445
[2358]446/**
447 * Complete VMDK image data structure. Mainly a collection of extents and a few
448 * extra global data fields.
449 */
450typedef struct VMDKIMAGE
451{
[32536]452 /** Image name. */
[32553]453 const char *pszFilename;
[2358]454 /** Descriptor file if applicable. */
[32553]455 PVMDKFILE pFile;
[97839]456
[11444]457 /** Pointer to the per-disk VD interface list. */
[32553]458 PVDINTERFACE pVDIfsDisk;
[28620]459 /** Pointer to the per-image VD interface list. */
[32553]460 PVDINTERFACE pVDIfsImage;
[97839]461
[10715]462 /** Error interface. */
[38469]463 PVDINTERFACEERROR pIfError;
464 /** I/O interface. */
465 PVDINTERFACEIOINT pIfIo;
[97839]466
467
[32536]468 /** Pointer to the image extents. */
469 PVMDKEXTENT pExtents;
470 /** Number of image extents. */
471 unsigned cExtents;
472 /** Pointer to the files list, for opening a file referenced multiple
473 * times only once (happens mainly with raw partition access). */
474 PVMDKFILE pFiles;
[97839]475
[11266]476 /**
[20167]477 * Pointer to an array of segment entries for async I/O.
[10715]478 * This is an optimization because the task number to submit is not known
479 * and allocating/freeing an array in the read/write functions every time
480 * is too expensive.
481 */
[20167]482 PPDMDATASEG paSegments;
483 /** Entries available in the segments array. */
484 unsigned cSegments;
[97839]485
[2358]486 /** Open flags passed by VBoxHD layer. */
487 unsigned uOpenFlags;
[2661]488 /** Image flags defined during creation or determined during open. */
489 unsigned uImageFlags;
[2358]490 /** Total size of the image. */
491 uint64_t cbSize;
[6291]492 /** Physical geometry of this image. */
[32536]493 VDGEOMETRY PCHSGeometry;
[6291]494 /** Logical geometry of this image. */
[32536]495 VDGEOMETRY LCHSGeometry;
[2358]496 /** Image UUID. */
497 RTUUID ImageUuid;
498 /** Image modification UUID. */
499 RTUUID ModificationUuid;
500 /** Parent image UUID. */
501 RTUUID ParentUuid;
[7155]502 /** Parent image modification UUID. */
503 RTUUID ParentModificationUuid;
[97839]504
[6291]505 /** Pointer to grain table cache, if this image contains sparse extents. */
[2358]506 PVMDKGTCACHE pGTCache;
507 /** Pointer to the descriptor (NULL if no separate descriptor file). */
508 char *pDescData;
509 /** Allocation size of the descriptor file. */
510 size_t cbDescAlloc;
511 /** Parsed descriptor file content. */
512 VMDKDESCRIPTOR Descriptor;
[66486]513 /** The static region list. */
514 VDREGIONLIST RegionList;
[10715]515} VMDKIMAGE;
[97839]516
517
[33088]518/** State for the input/output callout of the inflate reader/deflate writer. */
519typedef struct VMDKCOMPRESSIO
[16827]520{
[32536]521 /* Image this operation relates to. */
522 PVMDKIMAGE pImage;
[16827]523 /* Current read position. */
524 ssize_t iOffset;
[32882]525 /* Size of the compressed grain buffer (available data). */
526 size_t cbCompGrain;
527 /* Pointer to the compressed grain buffer. */
528 void *pvCompGrain;
[33088]529} VMDKCOMPRESSIO;
[97839]530
531
[30863]532/** Tracks async grain allocation. */
533typedef struct VMDKGRAINALLOCASYNC
534{
535 /** Flag whether the allocation failed. */
536 bool fIoErr;
537 /** Current number of transfers pending.
538 * If reached 0 and there is an error the old state is restored. */
539 unsigned cIoXfersPending;
540 /** Sector number */
541 uint64_t uSector;
542 /** Flag whether the grain table needs to be updated. */
543 bool fGTUpdateNeeded;
544 /** Extent the allocation happens. */
545 PVMDKEXTENT pExtent;
[33088]546 /** Position of the new grain, required for the grain table update. */
547 uint64_t uGrainOffset;
[30863]548 /** Grain table sector. */
549 uint64_t uGTSector;
550 /** Backup grain table sector. */
551 uint64_t uRGTSector;
552} VMDKGRAINALLOCASYNC, *PVMDKGRAINALLOCASYNC;
[97839]553
[63826]554/**
555 * State information for vmdkRename() and helpers.
556 */
557typedef struct VMDKRENAMESTATE
558{
559 /** Array of old filenames. */
560 char **apszOldName;
561 /** Array of new filenames. */
562 char **apszNewName;
563 /** Array of new lines in the extent descriptor. */
564 char **apszNewLines;
565 /** Name of the old descriptor file if not a sparse image. */
566 char *pszOldDescName;
567 /** Flag whether we called vmdkFreeImage(). */
568 bool fImageFreed;
569 /** Flag whther the descriptor is embedded in the image (sparse) or
570 * in a separate file. */
571 bool fEmbeddedDesc;
572 /** Number of extents in the image. */
573 unsigned cExtents;
574 /** New base filename. */
575 char *pszNewBaseName;
576 /** The old base filename. */
577 char *pszOldBaseName;
578 /** New full filename. */
579 char *pszNewFullName;
580 /** Old full filename. */
581 char *pszOldFullName;
582 /** The old image name. */
583 const char *pszOldImageName;
584 /** Copy of the original VMDK descriptor. */
585 VMDKDESCRIPTOR DescriptorCopy;
586 /** Copy of the extent state for sparse images. */
587 VMDKEXTENT ExtentCopy;
588} VMDKRENAMESTATE;
589/** Pointer to a VMDK rename state. */
590typedef VMDKRENAMESTATE *PVMDKRENAMESTATE;
[87054]591
592
[57358]593/*********************************************************************************************************************************
594* Static Variables *
595*********************************************************************************************************************************/
[97839]596
[11421]597/** NULL-terminated array of supported file extensions. */
[33524]598static const VDFILEEXTENSION s_aVmdkFileExtensions[] =
[11421]599{
[33524]600 {"vmdk", VDTYPE_HDD},
601 {NULL, VDTYPE_INVALID}
[11421]602};
[97839]603
[85902]604/** NULL-terminated array of configuration option. */
605static const VDCONFIGINFO s_aVmdkConfigInfo[] =
606{
607 /* Options for VMDK raw disks */
608 { "RawDrive", NULL, VDCFGVALUETYPE_STRING, 0 },
609 { "Partitions", NULL, VDCFGVALUETYPE_STRING, 0 },
610 { "BootSector", NULL, VDCFGVALUETYPE_BYTES, 0 },
611 { "Relative", NULL, VDCFGVALUETYPE_INTEGER, 0 },
[97839]612
[85902]613 /* End of options list */
614 { NULL, NULL, VDCFGVALUETYPE_INTEGER, 0 }
615};
[87054]616
617
[57358]618/*********************************************************************************************************************************
619* Internal Functions *
620*********************************************************************************************************************************/
[97839]621
[33182]622static void vmdkFreeStreamBuffers(PVMDKEXTENT pExtent);
[46613]623static int vmdkFreeExtentData(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
624 bool fDelete);
[97839]625
[2358]626static int vmdkCreateExtents(PVMDKIMAGE pImage, unsigned cExtents);
[44252]627static int vmdkFlushImage(PVMDKIMAGE pImage, PVDIOCTX pIoCtx);
[2742]628static int vmdkSetImageComment(PVMDKIMAGE pImage, const char *pszComment);
[76904]629static int vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete, bool fFlush);
[97839]630
[57388]631static DECLCALLBACK(int) vmdkAllocGrainComplete(void *pBackendData, PVDIOCTX pIoCtx,
632 void *pvUser, int rcReq);
[97839]633
[7155]634/**
[7576]635 * Internal: open a file (using a file descriptor cache to ensure each file
636 * is only opened once - anything else can cause locking problems).
637 */
[10715]638static int vmdkFileOpen(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile,
[85105]639 const char *pszBasename, const char *pszFilename, uint32_t fOpen)
[7576]640{
641 int rc = VINF_SUCCESS;
642 PVMDKFILE pVmdkFile;
[97839]643
[7576]644 for (pVmdkFile = pImage->pFiles;
645 pVmdkFile != NULL;
646 pVmdkFile = pVmdkFile->pNext)
647 {
648 if (!strcmp(pszFilename, pVmdkFile->pszFilename))
649 {
650 Assert(fOpen == pVmdkFile->fOpen);
651 pVmdkFile->uReferences++;
[97839]652
[10715]653 *ppVmdkFile = pVmdkFile;
[97839]654
[7576]655 return rc;
656 }
657 }
[97839]658
[7576]659 /* If we get here, there's no matching entry in the cache. */
660 pVmdkFile = (PVMDKFILE)RTMemAllocZ(sizeof(VMDKFILE));
[54117]661 if (!pVmdkFile)
[7576]662 {
[10715]663 *ppVmdkFile = NULL;
[7576]664 return VERR_NO_MEMORY;
665 }
[97839]666
[7576]667 pVmdkFile->pszFilename = RTStrDup(pszFilename);
[54117]668 if (!pVmdkFile->pszFilename)
[7576]669 {
670 RTMemFree(pVmdkFile);
[10715]671 *ppVmdkFile = NULL;
[7576]672 return VERR_NO_MEMORY;
673 }
[97839]674
[85105]675 if (pszBasename)
676 {
677 pVmdkFile->pszBasename = RTStrDup(pszBasename);
678 if (!pVmdkFile->pszBasename)
679 {
680 RTStrFree((char *)(void *)pVmdkFile->pszFilename);
681 RTMemFree(pVmdkFile);
682 *ppVmdkFile = NULL;
683 return VERR_NO_MEMORY;
684 }
685 }
[97839]686
[7576]687 pVmdkFile->fOpen = fOpen;
[97839]688
[38469]689 rc = vdIfIoIntFileOpen(pImage->pIfIo, pszFilename, fOpen,
690 &pVmdkFile->pStorage);
[11266]691 if (RT_SUCCESS(rc))
[7576]692 {
693 pVmdkFile->uReferences = 1;
[10715]694 pVmdkFile->pImage = pImage;
[7576]695 pVmdkFile->pNext = pImage->pFiles;
[10715]696 if (pImage->pFiles)
697 pImage->pFiles->pPrev = pVmdkFile;
[7576]698 pImage->pFiles = pVmdkFile;
[10715]699 *ppVmdkFile = pVmdkFile;
[7576]700 }
701 else
702 {
[7580]703 RTStrFree((char *)(void *)pVmdkFile->pszFilename);
[7576]704 RTMemFree(pVmdkFile);
[10715]705 *ppVmdkFile = NULL;
[7576]706 }
[97839]707
[7576]708 return rc;
709}
[97839]710
[7576]711/**
712 * Internal: close a file, updating the file descriptor cache.
713 */
[10715]714static int vmdkFileClose(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile, bool fDelete)
[7576]715{
716 int rc = VINF_SUCCESS;
[10715]717 PVMDKFILE pVmdkFile = *ppVmdkFile;
[97839]718
[14281]719 AssertPtr(pVmdkFile);
[97839]720
[10715]721 pVmdkFile->fDelete |= fDelete;
722 Assert(pVmdkFile->uReferences);
723 pVmdkFile->uReferences--;
724 if (pVmdkFile->uReferences == 0)
[7576]725 {
[10715]726 PVMDKFILE pPrev;
727 PVMDKFILE pNext;
[97839]728
[10715]729 /* Unchain the element from the list. */
730 pPrev = pVmdkFile->pPrev;
731 pNext = pVmdkFile->pNext;
[97839]732
[10715]733 if (pNext)
734 pNext->pPrev = pPrev;
735 if (pPrev)
736 pPrev->pNext = pNext;
737 else
738 pImage->pFiles = pNext;
[97839]739
[38469]740 rc = vdIfIoIntFileClose(pImage->pIfIo, pVmdkFile->pStorage);
[97839]741
[85105]742 bool fFileDel = pVmdkFile->fDelete;
743 if ( pVmdkFile->pszBasename
744 && fFileDel)
[68787]745 {
[85105]746 const char *pszSuffix = RTPathSuffix(pVmdkFile->pszBasename);
747 if ( RTPathHasPath(pVmdkFile->pszBasename)
748 || !pszSuffix
749 || ( strcmp(pszSuffix, ".vmdk")
750 && strcmp(pszSuffix, ".bin")
751 && strcmp(pszSuffix, ".img")))
752 fFileDel = false;
753 }
[97839]754
[85105]755 if (fFileDel)
756 {
[68787]757 int rc2 = vdIfIoIntFileDelete(pImage->pIfIo, pVmdkFile->pszFilename);
758 if (RT_SUCCESS(rc))
759 rc = rc2;
760 }
[85105]761 else if (pVmdkFile->fDelete)
762 LogRel(("VMDK: Denying deletion of %s\n", pVmdkFile->pszBasename));
[10715]763 RTStrFree((char *)(void *)pVmdkFile->pszFilename);
[85105]764 if (pVmdkFile->pszBasename)
765 RTStrFree((char *)(void *)pVmdkFile->pszBasename);
[10715]766 RTMemFree(pVmdkFile);
[7576]767 }
[97839]768
[10715]769 *ppVmdkFile = NULL;
770 return rc;
[7576]771}
[97839]772
[49231]773/*#define VMDK_USE_BLOCK_DECOMP_API - test and enable */
774#ifndef VMDK_USE_BLOCK_DECOMP_API
[16827]775static DECLCALLBACK(int) vmdkFileInflateHelper(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbBuf)
776{
[33088]777 VMDKCOMPRESSIO *pInflateState = (VMDKCOMPRESSIO *)pvUser;
[32882]778 size_t cbInjected = 0;
[97839]779
[16827]780 Assert(cbBuf);
781 if (pInflateState->iOffset < 0)
782 {
783 *(uint8_t *)pvBuf = RTZIPTYPE_ZLIB;
[32882]784 pvBuf = (uint8_t *)pvBuf + 1;
785 cbBuf--;
786 cbInjected = 1;
[73097]787 pInflateState->iOffset = RT_UOFFSETOF(VMDKMARKER, uType);
[32882]788 }
789 if (!cbBuf)
790 {
[16827]791 if (pcbBuf)
[32882]792 *pcbBuf = cbInjected;
[16827]793 return VINF_SUCCESS;
794 }
[32882]795 cbBuf = RT_MIN(cbBuf, pInflateState->cbCompGrain - pInflateState->iOffset);
796 memcpy(pvBuf,
797 (uint8_t *)pInflateState->pvCompGrain + pInflateState->iOffset,
798 cbBuf);
[16827]799 pInflateState->iOffset += cbBuf;
800 Assert(pcbBuf);
[32882]801 *pcbBuf = cbBuf + cbInjected;
[16827]802 return VINF_SUCCESS;
803}
[49231]804#endif
[97839]805
[10715]806/**
[16827]807 * Internal: read from a file and inflate the compressed data,
808 * distinguishing between async and normal operation
809 */
[32882]810DECLINLINE(int) vmdkFileInflateSync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
[32536]811 uint64_t uOffset, void *pvBuf,
[33182]812 size_t cbToRead, const void *pcvMarker,
813 uint64_t *puLBA, uint32_t *pcbMarkerData)
[16827]814{
[44252]815 int rc;
[49231]816#ifndef VMDK_USE_BLOCK_DECOMP_API
[44252]817 PRTZIPDECOMP pZip = NULL;
[49231]818#endif
[44252]819 VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
820 size_t cbCompSize, cbActuallyRead;
[97839]821
[44252]822 if (!pcvMarker)
[16827]823 {
[44252]824 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
[73097]825 uOffset, pMarker, RT_UOFFSETOF(VMDKMARKER, uType));
[44252]826 if (RT_FAILURE(rc))
827 return rc;
[16827]828 }
829 else
830 {
[73097]831 memcpy(pMarker, pcvMarker, RT_UOFFSETOF(VMDKMARKER, uType));
[44252]832 /* pcvMarker endianness has already been partially transformed, fix it */
833 pMarker->uSector = RT_H2LE_U64(pMarker->uSector);
834 pMarker->cbSize = RT_H2LE_U32(pMarker->cbSize);
835 }
[97839]836
[44252]837 cbCompSize = RT_LE2H_U32(pMarker->cbSize);
838 if (cbCompSize == 0)
839 {
840 AssertMsgFailed(("VMDK: corrupted marker\n"));
841 return VERR_VD_VMDK_INVALID_FORMAT;
842 }
[97839]843
[44252]844 /* Sanity check - the expansion ratio should be much less than 2. */
845 Assert(cbCompSize < 2 * cbToRead);
846 if (cbCompSize >= 2 * cbToRead)
847 return VERR_VD_VMDK_INVALID_FORMAT;
[97839]848
[44252]849 /* Compressed grain marker. Data follows immediately. */
850 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
[73097]851 uOffset + RT_UOFFSETOF(VMDKMARKER, uType),
[44252]852 (uint8_t *)pExtent->pvCompGrain
[73097]853 + RT_UOFFSETOF(VMDKMARKER, uType),
[44252]854 RT_ALIGN_Z( cbCompSize
[73097]855 + RT_UOFFSETOF(VMDKMARKER, uType),
[44252]856 512)
[73097]857 - RT_UOFFSETOF(VMDKMARKER, uType));
[97839]858
[44252]859 if (puLBA)
860 *puLBA = RT_LE2H_U64(pMarker->uSector);
861 if (pcbMarkerData)
862 *pcbMarkerData = RT_ALIGN( cbCompSize
[73097]863 + RT_UOFFSETOF(VMDKMARKER, uType),
[44252]864 512);
[97839]865
[49231]866#ifdef VMDK_USE_BLOCK_DECOMP_API
867 rc = RTZipBlockDecompress(RTZIPTYPE_ZLIB, 0 /*fFlags*/,
[73097]868 pExtent->pvCompGrain, cbCompSize + RT_UOFFSETOF(VMDKMARKER, uType), NULL,
[49231]869 pvBuf, cbToRead, &cbActuallyRead);
870#else
[44252]871 VMDKCOMPRESSIO InflateState;
872 InflateState.pImage = pImage;
873 InflateState.iOffset = -1;
[73097]874 InflateState.cbCompGrain = cbCompSize + RT_UOFFSETOF(VMDKMARKER, uType);
[44252]875 InflateState.pvCompGrain = pExtent->pvCompGrain;
[97839]876
[44252]877 rc = RTZipDecompCreate(&pZip, &InflateState, vmdkFileInflateHelper);
878 if (RT_FAILURE(rc))
[16827]879 return rc;
[44252]880 rc = RTZipDecompress(pZip, pvBuf, cbToRead, &cbActuallyRead);
881 RTZipDecompDestroy(pZip);
[49231]882#endif /* !VMDK_USE_BLOCK_DECOMP_API */
[44252]883 if (RT_FAILURE(rc))
884 {
885 if (rc == VERR_ZIP_CORRUPTED)
886 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: Compressed image is corrupted '%s'"), pExtent->pszFullname);
887 return rc;
[16827]888 }
[44252]889 if (cbActuallyRead != cbToRead)
890 rc = VERR_VD_VMDK_INVALID_FORMAT;
891 return rc;
[16827]892}
[97839]893
[17775]894static DECLCALLBACK(int) vmdkFileDeflateHelper(void *pvUser, const void *pvBuf, size_t cbBuf)
895{
[33088]896 VMDKCOMPRESSIO *pDeflateState = (VMDKCOMPRESSIO *)pvUser;
[97839]897
[17775]898 Assert(cbBuf);
899 if (pDeflateState->iOffset < 0)
900 {
901 pvBuf = (const uint8_t *)pvBuf + 1;
902 cbBuf--;
[73097]903 pDeflateState->iOffset = RT_UOFFSETOF(VMDKMARKER, uType);
[17775]904 }
905 if (!cbBuf)
906 return VINF_SUCCESS;
[32882]907 if (pDeflateState->iOffset + cbBuf > pDeflateState->cbCompGrain)
908 return VERR_BUFFER_OVERFLOW;
909 memcpy((uint8_t *)pDeflateState->pvCompGrain + pDeflateState->iOffset,
910 pvBuf, cbBuf);
[17775]911 pDeflateState->iOffset += cbBuf;
912 return VINF_SUCCESS;
913}
[97839]914
[16827]915/**
[17775]916 * Internal: deflate the uncompressed data and write to a file,
917 * distinguishing between async and normal operation
918 */
[32882]919DECLINLINE(int) vmdkFileDeflateSync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
[32536]920 uint64_t uOffset, const void *pvBuf,
[32882]921 size_t cbToWrite, uint64_t uLBA,
922 uint32_t *pcbMarkerData)
[17775]923{
[44252]924 int rc;
925 PRTZIPCOMP pZip = NULL;
926 VMDKCOMPRESSIO DeflateState;
[97839]927
[44252]928 DeflateState.pImage = pImage;
929 DeflateState.iOffset = -1;
930 DeflateState.cbCompGrain = pExtent->cbCompGrain;
931 DeflateState.pvCompGrain = pExtent->pvCompGrain;
[97839]932
[44252]933 rc = RTZipCompCreate(&pZip, &DeflateState, vmdkFileDeflateHelper,
934 RTZIPTYPE_ZLIB, RTZIPLEVEL_DEFAULT);
935 if (RT_FAILURE(rc))
936 return rc;
937 rc = RTZipCompress(pZip, pvBuf, cbToWrite);
938 if (RT_SUCCESS(rc))
939 rc = RTZipCompFinish(pZip);
940 RTZipCompDestroy(pZip);
941 if (RT_SUCCESS(rc))
[17775]942 {
[44252]943 Assert( DeflateState.iOffset > 0
944 && (size_t)DeflateState.iOffset <= DeflateState.cbCompGrain);
[97839]945
[44252]946 /* pad with zeroes to get to a full sector size */
947 uint32_t uSize = DeflateState.iOffset;
948 if (uSize % 512)
949 {
950 uint32_t uSizeAlign = RT_ALIGN(uSize, 512);
951 memset((uint8_t *)pExtent->pvCompGrain + uSize, '\0',
952 uSizeAlign - uSize);
953 uSize = uSizeAlign;
954 }
[97839]955
[44252]956 if (pcbMarkerData)
957 *pcbMarkerData = uSize;
[97839]958
[44252]959 /* Compressed grain marker. Data follows immediately. */
960 VMDKMARKER *pMarker = (VMDKMARKER *)pExtent->pvCompGrain;
961 pMarker->uSector = RT_H2LE_U64(uLBA);
962 pMarker->cbSize = RT_H2LE_U32( DeflateState.iOffset
[73097]963 - RT_UOFFSETOF(VMDKMARKER, uType));
[44252]964 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
965 uOffset, pMarker, uSize);
[17775]966 if (RT_FAILURE(rc))
967 return rc;
968 }
[44252]969 return rc;
[17775]970}
[97839]971
972
[17775]973/**
[7576]974 * Internal: check if all files are closed, prevent leaking resources.
975 */
976static int vmdkFileCheckAllClose(PVMDKIMAGE pImage)
977{
978 int rc = VINF_SUCCESS, rc2;
979 PVMDKFILE pVmdkFile;
[97839]980
[7576]981 Assert(pImage->pFiles == NULL);
982 for (pVmdkFile = pImage->pFiles;
983 pVmdkFile != NULL;
984 pVmdkFile = pVmdkFile->pNext)
985 {
986 LogRel(("VMDK: leaking reference to file \"%s\"\n",
987 pVmdkFile->pszFilename));
988 pImage->pFiles = pVmdkFile->pNext;
[97839]989
[32536]990 rc2 = vmdkFileClose(pImage, &pVmdkFile, pVmdkFile->fDelete);
[97839]991
[11266]992 if (RT_SUCCESS(rc))
[7576]993 rc = rc2;
994 }
995 return rc;
996}
[97839]997
[7576]998/**
[2742]999 * Internal: truncate a string (at a UTF8 code point boundary) and encode the
1000 * critical non-ASCII characters.
1001 */
1002static char *vmdkEncodeString(const char *psz)
1003{
[7580]1004 char szEnc[VMDK_ENCODED_COMMENT_MAX + 3];
[7576]1005 char *pszDst = szEnc;
[97839]1006
[14281]1007 AssertPtr(psz);
[97839]1008
[7576]1009 for (; *psz; psz = RTStrNextCp(psz))
1010 {
1011 char *pszDstPrev = pszDst;
1012 RTUNICP Cp = RTStrGetCp(psz);
1013 if (Cp == '\\')
1014 {
1015 pszDst = RTStrPutCp(pszDst, Cp);
1016 pszDst = RTStrPutCp(pszDst, Cp);
1017 }
1018 else if (Cp == '\n')
1019 {
1020 pszDst = RTStrPutCp(pszDst, '\\');
1021 pszDst = RTStrPutCp(pszDst, 'n');
1022 }
1023 else if (Cp == '\r')
1024 {
1025 pszDst = RTStrPutCp(pszDst, '\\');
1026 pszDst = RTStrPutCp(pszDst, 'r');
1027 }
1028 else
1029 pszDst = RTStrPutCp(pszDst, Cp);
[7580]1030 if (pszDst - szEnc >= VMDK_ENCODED_COMMENT_MAX - 1)
[7576]1031 {
1032 pszDst = pszDstPrev;
1033 break;
1034 }
1035 }
1036 *pszDst = '\0';
1037 return RTStrDup(szEnc);
[2742]1038}
[97839]1039
[2742]1040/**
1041 * Internal: decode a string and store it into the specified string.
1042 */
1043static int vmdkDecodeString(const char *pszEncoded, char *psz, size_t cb)
1044{
[7576]1045 int rc = VINF_SUCCESS;
1046 char szBuf[4];
[97839]1047
[2742]1048 if (!cb)
[7576]1049 return VERR_BUFFER_OVERFLOW;
[97839]1050
[14281]1051 AssertPtr(psz);
[97839]1052
[7576]1053 for (; *pszEncoded; pszEncoded = RTStrNextCp(pszEncoded))
1054 {
1055 char *pszDst = szBuf;
1056 RTUNICP Cp = RTStrGetCp(pszEncoded);
1057 if (Cp == '\\')
1058 {
1059 pszEncoded = RTStrNextCp(pszEncoded);
1060 RTUNICP CpQ = RTStrGetCp(pszEncoded);
1061 if (CpQ == 'n')
1062 RTStrPutCp(pszDst, '\n');
1063 else if (CpQ == 'r')
1064 RTStrPutCp(pszDst, '\r');
1065 else if (CpQ == '\0')
1066 {
[15366]1067 rc = VERR_VD_VMDK_INVALID_HEADER;
[7576]1068 break;
1069 }
1070 else
1071 RTStrPutCp(pszDst, CpQ);
1072 }
1073 else
1074 pszDst = RTStrPutCp(pszDst, Cp);
[97839]1075
[7576]1076 /* Need to leave space for terminating NUL. */
1077 if ((size_t)(pszDst - szBuf) + 1 >= cb)
1078 {
1079 rc = VERR_BUFFER_OVERFLOW;
1080 break;
1081 }
1082 memcpy(psz, szBuf, pszDst - szBuf);
1083 psz += pszDst - szBuf;
1084 }
1085 *psz = '\0';
1086 return rc;
[2742]1087}
[97839]1088
[32883]1089/**
1090 * Internal: free all buffers associated with grain directories.
1091 */
1092static void vmdkFreeGrainDirectory(PVMDKEXTENT pExtent)
1093{
1094 if (pExtent->pGD)
1095 {
1096 RTMemFree(pExtent->pGD);
1097 pExtent->pGD = NULL;
1098 }
1099 if (pExtent->pRGD)
1100 {
1101 RTMemFree(pExtent->pRGD);
1102 pExtent->pRGD = NULL;
1103 }
1104}
[97839]1105
[32883]1106/**
[33182]1107 * Internal: allocate the compressed/uncompressed buffers for streamOptimized
1108 * images.
[32883]1109 */
[33182]1110static int vmdkAllocStreamBuffers(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
[32883]1111{
[32884]1112 int rc = VINF_SUCCESS;
[97839]1113
[32883]1114 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
1115 {
1116 /* streamOptimized extents need a compressed grain buffer, which must
1117 * be big enough to hold uncompressible data (which needs ~8 bytes
1118 * more than the uncompressed data), the marker and padding. */
1119 pExtent->cbCompGrain = RT_ALIGN_Z( VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
1120 + 8 + sizeof(VMDKMARKER), 512);
1121 pExtent->pvCompGrain = RTMemAlloc(pExtent->cbCompGrain);
[63798]1122 if (RT_LIKELY(pExtent->pvCompGrain))
[32883]1123 {
[63798]1124 /* streamOptimized extents need a decompressed grain buffer. */
1125 pExtent->pvGrain = RTMemAlloc(VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
1126 if (!pExtent->pvGrain)
1127 rc = VERR_NO_MEMORY;
[32883]1128 }
[63798]1129 else
[32883]1130 rc = VERR_NO_MEMORY;
1131 }
[97839]1132
[32883]1133 if (RT_FAILURE(rc))
[33182]1134 vmdkFreeStreamBuffers(pExtent);
1135 return rc;
1136}
[97839]1137
[33182]1138/**
1139 * Internal: allocate all buffers associated with grain directories.
1140 */
1141static int vmdkAllocGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
1142{
[62755]1143 RT_NOREF1(pImage);
[33182]1144 int rc = VINF_SUCCESS;
1145 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
[97839]1146
[63798]1147 pExtent->pGD = (uint32_t *)RTMemAllocZ(cbGD);
1148 if (RT_LIKELY(pExtent->pGD))
[33182]1149 {
[63798]1150 if (pExtent->uSectorRGD)
[33182]1151 {
[63798]1152 pExtent->pRGD = (uint32_t *)RTMemAllocZ(cbGD);
1153 if (RT_UNLIKELY(!pExtent->pRGD))
1154 rc = VERR_NO_MEMORY;
[33182]1155 }
1156 }
[63798]1157 else
1158 rc = VERR_NO_MEMORY;
[97839]1159
[33182]1160 if (RT_FAILURE(rc))
[32883]1161 vmdkFreeGrainDirectory(pExtent);
1162 return rc;
1163}
[97839]1164
[63798]1165/**
1166 * Converts the grain directory from little to host endianess.
1167 *
1168 * @param pGD The grain directory.
1169 * @param cGDEntries Number of entries in the grain directory to convert.
1170 */
1171DECLINLINE(void) vmdkGrainDirectoryConvToHost(uint32_t *pGD, uint32_t cGDEntries)
1172{
1173 uint32_t *pGDTmp = pGD;
[97839]1174
[63798]1175 for (uint32_t i = 0; i < cGDEntries; i++, pGDTmp++)
1176 *pGDTmp = RT_LE2H_U32(*pGDTmp);
1177}
[97839]1178
[63798]1179/**
1180 * Read the grain directory and allocated grain tables verifying them against
1181 * their back up copies if available.
1182 *
1183 * @returns VBox status code.
1184 * @param pImage Image instance data.
1185 * @param pExtent The VMDK extent.
1186 */
[32536]1187static int vmdkReadGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
[2358]1188{
1189 int rc = VINF_SUCCESS;
1190 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
[97839]1191
[63798]1192 AssertReturn(( pExtent->enmType == VMDKETYPE_HOSTED_SPARSE
1193 && pExtent->uSectorGD != VMDK_GD_AT_END
1194 && pExtent->uSectorRGD != VMDK_GD_AT_END), VERR_INTERNAL_ERROR);
[97839]1195
[32883]1196 rc = vmdkAllocGrainDirectory(pImage, pExtent);
[63798]1197 if (RT_SUCCESS(rc))
[2358]1198 {
[32573]1199 /* The VMDK 1.1 spec seems to talk about compressed grain directories,
1200 * but in reality they are not compressed. */
[38469]1201 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
[63798]1202 VMDK_SECTOR2BYTE(pExtent->uSectorGD),
1203 pExtent->pGD, cbGD);
1204 if (RT_SUCCESS(rc))
[2358]1205 {
[63798]1206 vmdkGrainDirectoryConvToHost(pExtent->pGD, pExtent->cGDEntries);
[97839]1207
[63798]1208 if ( pExtent->uSectorRGD
1209 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS))
1210 {
1211 /* The VMDK 1.1 spec seems to talk about compressed grain directories,
1212 * but in reality they are not compressed. */
1213 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
1214 VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
1215 pExtent->pRGD, cbGD);
1216 if (RT_SUCCESS(rc))
1217 {
1218 vmdkGrainDirectoryConvToHost(pExtent->pRGD, pExtent->cGDEntries);
[97839]1219
[63798]1220 /* Check grain table and redundant grain table for consistency. */
1221 size_t cbGT = pExtent->cGTEntries * sizeof(uint32_t);
1222 size_t cbGTBuffers = cbGT; /* Start with space for one GT. */
1223 size_t cbGTBuffersMax = _1M;
[97839]1224
[63798]1225 uint32_t *pTmpGT1 = (uint32_t *)RTMemAlloc(cbGTBuffers);
1226 uint32_t *pTmpGT2 = (uint32_t *)RTMemAlloc(cbGTBuffers);
[97839]1227
[63798]1228 if ( !pTmpGT1
1229 || !pTmpGT2)
1230 rc = VERR_NO_MEMORY;
[97839]1231
[63801]1232 size_t i = 0;
[63798]1233 uint32_t *pGDTmp = pExtent->pGD;
1234 uint32_t *pRGDTmp = pExtent->pRGD;
[97839]1235
[63798]1236 /* Loop through all entries. */
1237 while (i < pExtent->cGDEntries)
1238 {
1239 uint32_t uGTStart = *pGDTmp;
1240 uint32_t uRGTStart = *pRGDTmp;
1241 size_t cbGTRead = cbGT;
[97839]1242
[63798]1243 /* If no grain table is allocated skip the entry. */
1244 if (*pGDTmp == 0 && *pRGDTmp == 0)
1245 {
1246 i++;
1247 continue;
1248 }
[97839]1249
[63798]1250 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
1251 {
1252 /* Just one grain directory entry refers to a not yet allocated
1253 * grain table or both grain directory copies refer to the same
1254 * grain table. Not allowed. */
1255 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
1256 N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname);
1257 break;
1258 }
[97839]1259
[63798]1260 i++;
1261 pGDTmp++;
1262 pRGDTmp++;
[97839]1263
[63798]1264 /*
1265 * Read a few tables at once if adjacent to decrease the number
1266 * of I/O requests. Read at maximum 1MB at once.
1267 */
1268 while ( i < pExtent->cGDEntries
1269 && cbGTRead < cbGTBuffersMax)
1270 {
1271 /* If no grain table is allocated skip the entry. */
1272 if (*pGDTmp == 0 && *pRGDTmp == 0)
1273 {
1274 i++;
1275 continue;
1276 }
[97839]1277
[63798]1278 if (*pGDTmp == 0 || *pRGDTmp == 0 || *pGDTmp == *pRGDTmp)
1279 {
1280 /* Just one grain directory entry refers to a not yet allocated
1281 * grain table or both grain directory copies refer to the same
1282 * grain table. Not allowed. */
1283 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
1284 N_("VMDK: inconsistent references to grain directory in '%s'"), pExtent->pszFullname);
1285 break;
1286 }
[97839]1287
[63798]1288 /* Check that the start offsets are adjacent.*/
1289 if ( VMDK_SECTOR2BYTE(uGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pGDTmp)
1290 || VMDK_SECTOR2BYTE(uRGTStart) + cbGTRead != VMDK_SECTOR2BYTE(*pRGDTmp))
1291 break;
[97839]1292
[63798]1293 i++;
1294 pGDTmp++;
1295 pRGDTmp++;
1296 cbGTRead += cbGT;
1297 }
[97839]1298
[63798]1299 /* Increase buffers if required. */
1300 if ( RT_SUCCESS(rc)
1301 && cbGTBuffers < cbGTRead)
1302 {
1303 uint32_t *pTmp;
1304 pTmp = (uint32_t *)RTMemRealloc(pTmpGT1, cbGTRead);
1305 if (pTmp)
1306 {
1307 pTmpGT1 = pTmp;
1308 pTmp = (uint32_t *)RTMemRealloc(pTmpGT2, cbGTRead);
1309 if (pTmp)
1310 pTmpGT2 = pTmp;
1311 else
1312 rc = VERR_NO_MEMORY;
1313 }
1314 else
1315 rc = VERR_NO_MEMORY;
[97839]1316
[63798]1317 if (rc == VERR_NO_MEMORY)
1318 {
1319 /* Reset to the old values. */
1320 rc = VINF_SUCCESS;
1321 i -= cbGTRead / cbGT;
1322 cbGTRead = cbGT;
[97839]1323
[63798]1324 /* Don't try to increase the buffer again in the next run. */
1325 cbGTBuffersMax = cbGTBuffers;
1326 }
1327 }
[97839]1328
[63798]1329 if (RT_SUCCESS(rc))
1330 {
1331 /* The VMDK 1.1 spec seems to talk about compressed grain tables,
1332 * but in reality they are not compressed. */
1333 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
1334 VMDK_SECTOR2BYTE(uGTStart),
1335 pTmpGT1, cbGTRead);
1336 if (RT_FAILURE(rc))
1337 {
1338 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1339 N_("VMDK: error reading grain table in '%s'"), pExtent->pszFullname);
1340 break;
1341 }
1342 /* The VMDK 1.1 spec seems to talk about compressed grain tables,
1343 * but in reality they are not compressed. */
1344 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
1345 VMDK_SECTOR2BYTE(uRGTStart),
1346 pTmpGT2, cbGTRead);
1347 if (RT_FAILURE(rc))
1348 {
1349 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1350 N_("VMDK: error reading backup grain table in '%s'"), pExtent->pszFullname);
1351 break;
1352 }
1353 if (memcmp(pTmpGT1, pTmpGT2, cbGTRead))
1354 {
1355 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
1356 N_("VMDK: inconsistency between grain table and backup grain table in '%s'"), pExtent->pszFullname);
1357 break;
1358 }
1359 }
1360 } /* while (i < pExtent->cGDEntries) */
[97839]1361
[63798]1362 /** @todo figure out what to do for unclean VMDKs. */
1363 if (pTmpGT1)
1364 RTMemFree(pTmpGT1);
1365 if (pTmpGT2)
1366 RTMemFree(pTmpGT2);
[41767]1367 }
[63798]1368 else
[41767]1369 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
[63798]1370 N_("VMDK: could not read redundant grain directory in '%s'"), pExtent->pszFullname);
[2358]1371 }
[63798]1372 }
1373 else
1374 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS,
1375 N_("VMDK: could not read grain directory in '%s': %Rrc"), pExtent->pszFullname, rc);
[2358]1376 }
[97839]1377
[11266]1378 if (RT_FAILURE(rc))
[2358]1379 vmdkFreeGrainDirectory(pExtent);
1380 return rc;
1381}
[97839]1382
[63798]1383/**
1384 * Creates a new grain directory for the given extent at the given start sector.
1385 *
1386 * @returns VBox status code.
1387 * @param pImage Image instance data.
1388 * @param pExtent The VMDK extent.
1389 * @param uStartSector Where the grain directory should be stored in the image.
1390 * @param fPreAlloc Flag whether to pre allocate the grain tables at this point.
1391 */
[32536]1392static int vmdkCreateGrainDirectory(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
[96837]1393 uint64_t uStartSector, bool fPreAlloc)
[2650]1394{
1395 int rc = VINF_SUCCESS;
1396 unsigned i;
1397 size_t cbGD = pExtent->cGDEntries * sizeof(uint32_t);
[41767]1398 size_t cbGDRounded = RT_ALIGN_64(cbGD, 512);
[2650]1399 size_t cbGTRounded;
1400 uint64_t cbOverhead;
[97839]1401
[2650]1402 if (fPreAlloc)
[33088]1403 {
[2650]1404 cbGTRounded = RT_ALIGN_64(pExtent->cGDEntries * pExtent->cGTEntries * sizeof(uint32_t), 512);
[63798]1405 cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded + cbGTRounded;
[33088]1406 }
[2650]1407 else
[33088]1408 {
1409 /* Use a dummy start sector for layout computation. */
1410 if (uStartSector == VMDK_GD_AT_END)
1411 uStartSector = 1;
[2650]1412 cbGTRounded = 0;
[33088]1413 cbOverhead = VMDK_SECTOR2BYTE(uStartSector) + cbGDRounded;
1414 }
[97839]1415
[33088]1416 /* For streamOptimized extents there is only one grain directory,
1417 * and for all others take redundant grain directory into account. */
1418 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
[32536]1419 {
[33088]1420 cbOverhead = RT_ALIGN_64(cbOverhead,
1421 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
[32536]1422 }
[17775]1423 else
[32536]1424 {
[33088]1425 cbOverhead += cbGDRounded + cbGTRounded;
1426 cbOverhead = RT_ALIGN_64(cbOverhead,
1427 VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
[96837]1428 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pExtent->pFile->pStorage, cbOverhead);
[33088]1429 }
[97839]1430
[63798]1431 if (RT_SUCCESS(rc))
[33088]1432 {
[63798]1433 pExtent->uAppendPosition = cbOverhead;
1434 pExtent->cOverheadSectors = VMDK_BYTE2SECTOR(cbOverhead);
[97839]1435
[63798]1436 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
1437 {
1438 pExtent->uSectorRGD = 0;
1439 pExtent->uSectorGD = uStartSector;
1440 }
1441 else
1442 {
1443 pExtent->uSectorRGD = uStartSector;
1444 pExtent->uSectorGD = uStartSector + VMDK_BYTE2SECTOR(cbGDRounded + cbGTRounded);
1445 }
[97839]1446
[63798]1447 rc = vmdkAllocStreamBuffers(pImage, pExtent);
1448 if (RT_SUCCESS(rc))
[2650]1449 {
[63798]1450 rc = vmdkAllocGrainDirectory(pImage, pExtent);
1451 if ( RT_SUCCESS(rc)
1452 && fPreAlloc)
[17847]1453 {
[63798]1454 uint32_t uGTSectorLE;
1455 uint64_t uOffsetSectors;
[97839]1456
[63798]1457 if (pExtent->pRGD)
[32642]1458 {
[63798]1459 uOffsetSectors = pExtent->uSectorRGD + VMDK_BYTE2SECTOR(cbGDRounded);
1460 for (i = 0; i < pExtent->cGDEntries; i++)
1461 {
1462 pExtent->pRGD[i] = uOffsetSectors;
1463 uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
1464 /* Write the redundant grain directory entry to disk. */
1465 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
1466 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
1467 &uGTSectorLE, sizeof(uGTSectorLE));
1468 if (RT_FAILURE(rc))
1469 {
1470 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
1471 break;
1472 }
1473 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
1474 }
[32642]1475 }
[97839]1476
[63798]1477 if (RT_SUCCESS(rc))
1478 {
1479 uOffsetSectors = pExtent->uSectorGD + VMDK_BYTE2SECTOR(cbGDRounded);
1480 for (i = 0; i < pExtent->cGDEntries; i++)
1481 {
1482 pExtent->pGD[i] = uOffsetSectors;
1483 uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
1484 /* Write the grain directory entry to disk. */
1485 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pExtent->pFile->pStorage,
1486 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
1487 &uGTSectorLE, sizeof(uGTSectorLE));
1488 if (RT_FAILURE(rc))
1489 {
1490 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
1491 break;
1492 }
1493 uOffsetSectors += VMDK_BYTE2SECTOR(pExtent->cGTEntries * sizeof(uint32_t));
1494 }
1495 }
[17847]1496 }
[2650]1497 }
1498 }
[97839]1499
[11266]1500 if (RT_FAILURE(rc))
[2650]1501 vmdkFreeGrainDirectory(pExtent);
1502 return rc;
1503}
[97839]1504
[59609]1505/**
[64272]1506 * Unquotes the given string returning the result in a separate buffer.
1507 *
1508 * @returns VBox status code.
1509 * @param pImage The VMDK image state.
1510 * @param pszStr The string to unquote.
[59609]1511 * @param ppszUnquoted Where to store the return value, use RTMemTmpFree to
1512 * free.
[64272]1513 * @param ppszNext Where to store the pointer to any character following
1514 * the quoted value, optional.
[59609]1515 */
[6291]1516static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr,
1517 char **ppszUnquoted, char **ppszNext)
[2358]1518{
[61757]1519 const char *pszStart = pszStr;
[2358]1520 char *pszQ;
1521 char *pszUnquoted;
[97839]1522
[2358]1523 /* Skip over whitespace. */
1524 while (*pszStr == ' ' || *pszStr == '\t')
1525 pszStr++;
[97839]1526
[18347]1527 if (*pszStr != '"')
1528 {
1529 pszQ = (char *)pszStr;
1530 while (*pszQ && *pszQ != ' ' && *pszQ != '\t')
1531 pszQ++;
1532 }
1533 else
1534 {
1535 pszStr++;
1536 pszQ = (char *)strchr(pszStr, '"');
1537 if (pszQ == NULL)
[61757]1538 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrectly quoted value in descriptor in '%s' (raw value %s)"),
1539 pImage->pszFilename, pszStart);
[18347]1540 }
[97839]1541
[2358]1542 pszUnquoted = (char *)RTMemTmpAlloc(pszQ - pszStr + 1);
1543 if (!pszUnquoted)
1544 return VERR_NO_MEMORY;
1545 memcpy(pszUnquoted, pszStr, pszQ - pszStr);
1546 pszUnquoted[pszQ - pszStr] = '\0';
1547 *ppszUnquoted = pszUnquoted;
1548 if (ppszNext)
1549 *ppszNext = pszQ + 1;
1550 return VINF_SUCCESS;
1551}
[97839]1552
[2661]1553static int vmdkDescInitStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
[2650]1554 const char *pszLine)
1555{
1556 char *pEnd = pDescriptor->aLines[pDescriptor->cLines];
1557 ssize_t cbDiff = strlen(pszLine) + 1;
[97839]1558
[2650]1559 if ( pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1
1560 && pEnd - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
[38469]1561 return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
[97839]1562
[2650]1563 memcpy(pEnd, pszLine, cbDiff);
1564 pDescriptor->cLines++;
1565 pDescriptor->aLines[pDescriptor->cLines] = pEnd + cbDiff;
1566 pDescriptor->fDirty = true;
[97839]1567
[2650]1568 return VINF_SUCCESS;
1569}
[97839]1570
[2358]1571static bool vmdkDescGetStr(PVMDKDESCRIPTOR pDescriptor, unsigned uStart,
1572 const char *pszKey, const char **ppszValue)
1573{
1574 size_t cbKey = strlen(pszKey);
1575 const char *pszValue;
[97839]1576
[2358]1577 while (uStart != 0)
1578 {
1579 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
1580 {
[6291]1581 /* Key matches, check for a '=' (preceded by whitespace). */
[2358]1582 pszValue = pDescriptor->aLines[uStart] + cbKey;
1583 while (*pszValue == ' ' || *pszValue == '\t')
1584 pszValue++;
1585 if (*pszValue == '=')
1586 {
1587 *ppszValue = pszValue + 1;
1588 break;
1589 }
1590 }
1591 uStart = pDescriptor->aNextLines[uStart];
1592 }
1593 return !!uStart;
1594}
[97839]1595
[2358]1596static int vmdkDescSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1597 unsigned uStart,
1598 const char *pszKey, const char *pszValue)
1599{
[62757]1600 char *pszTmp = NULL; /* (MSC naturally cannot figure this isn't used uninitialized) */
[2358]1601 size_t cbKey = strlen(pszKey);
[2361]1602 unsigned uLast = 0;
[97839]1603
[2358]1604 while (uStart != 0)
1605 {
1606 if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
1607 {
[6291]1608 /* Key matches, check for a '=' (preceded by whitespace). */
[2358]1609 pszTmp = pDescriptor->aLines[uStart] + cbKey;
1610 while (*pszTmp == ' ' || *pszTmp == '\t')
1611 pszTmp++;
1612 if (*pszTmp == '=')
1613 {
[7846]1614 pszTmp++;
[62757]1615 /** @todo r=bird: Doesn't skipping trailing blanks here just cause unecessary
1616 * bloat and potentially out of space error? */
[2358]1617 while (*pszTmp == ' ' || *pszTmp == '\t')
1618 pszTmp++;
1619 break;
1620 }
1621 }
1622 if (!pDescriptor->aNextLines[uStart])
1623 uLast = uStart;
1624 uStart = pDescriptor->aNextLines[uStart];
1625 }
1626 if (uStart)
1627 {
[2742]1628 if (pszValue)
1629 {
1630 /* Key already exists, replace existing value. */
1631 size_t cbOldVal = strlen(pszTmp);
1632 size_t cbNewVal = strlen(pszValue);
1633 ssize_t cbDiff = cbNewVal - cbOldVal;
1634 /* Check for buffer overflow. */
[62756]1635 if ( pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[0]
1636 > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff)
[38469]1637 return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
[97839]1638
[2742]1639 memmove(pszTmp + cbNewVal, pszTmp + cbOldVal,
1640 pDescriptor->aLines[pDescriptor->cLines] - pszTmp - cbOldVal);
1641 memcpy(pszTmp, pszValue, cbNewVal + 1);
1642 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1643 pDescriptor->aLines[i] += cbDiff;
1644 }
1645 else
1646 {
1647 memmove(pDescriptor->aLines[uStart], pDescriptor->aLines[uStart+1],
1648 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uStart+1] + 1);
1649 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1650 {
1651 pDescriptor->aLines[i-1] = pDescriptor->aLines[i];
1652 if (pDescriptor->aNextLines[i])
1653 pDescriptor->aNextLines[i-1] = pDescriptor->aNextLines[i] - 1;
1654 else
1655 pDescriptor->aNextLines[i-1] = 0;
1656 }
1657 pDescriptor->cLines--;
1658 /* Adjust starting line numbers of following descriptor sections. */
1659 if (uStart < pDescriptor->uFirstExtent)
1660 pDescriptor->uFirstExtent--;
1661 if (uStart < pDescriptor->uFirstDDB)
1662 pDescriptor->uFirstDDB--;
1663 }
[2358]1664 }
1665 else
1666 {
[6291]1667 /* Key doesn't exist, append after the last entry in this category. */
[2742]1668 if (!pszValue)
1669 {
1670 /* Key doesn't exist, and it should be removed. Simply a no-op. */
1671 return VINF_SUCCESS;
1672 }
[25823]1673 cbKey = strlen(pszKey);
[2358]1674 size_t cbValue = strlen(pszValue);
1675 ssize_t cbDiff = cbKey + 1 + cbValue + 1;
1676 /* Check for buffer overflow. */
1677 if ( (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
1678 || ( pDescriptor->aLines[pDescriptor->cLines]
1679 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
[38469]1680 return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
[2358]1681 for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
1682 {
1683 pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
[2650]1684 if (pDescriptor->aNextLines[i - 1])
1685 pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
1686 else
1687 pDescriptor->aNextLines[i] = 0;
[2358]1688 }
1689 uStart = uLast + 1;
1690 pDescriptor->aNextLines[uLast] = uStart;
1691 pDescriptor->aNextLines[uStart] = 0;
1692 pDescriptor->cLines++;
1693 pszTmp = pDescriptor->aLines[uStart];
1694 memmove(pszTmp + cbDiff, pszTmp,
1695 pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
1696 memcpy(pDescriptor->aLines[uStart], pszKey, cbKey);
1697 pDescriptor->aLines[uStart][cbKey] = '=';
1698 memcpy(pDescriptor->aLines[uStart] + cbKey + 1, pszValue, cbValue + 1);
1699 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1700 pDescriptor->aLines[i] += cbDiff;
[97839]1701
[2650]1702 /* Adjust starting line numbers of following descriptor sections. */
1703 if (uStart <= pDescriptor->uFirstExtent)
1704 pDescriptor->uFirstExtent++;
1705 if (uStart <= pDescriptor->uFirstDDB)
1706 pDescriptor->uFirstDDB++;
[2358]1707 }
1708 pDescriptor->fDirty = true;
1709 return VINF_SUCCESS;
1710}
[97839]1711
[2358]1712static int vmdkDescBaseGetU32(PVMDKDESCRIPTOR pDescriptor, const char *pszKey,
1713 uint32_t *puValue)
1714{
1715 const char *pszValue;
[97839]1716
[6291]1717 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
1718 &pszValue))
[15366]1719 return VERR_VD_VMDK_VALUE_NOT_FOUND;
[2358]1720 return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
1721}
[97839]1722
[59609]1723/**
[64272]1724 * Returns the value of the given key as a string allocating the necessary memory.
1725 *
1726 * @returns VBox status code.
1727 * @retval VERR_VD_VMDK_VALUE_NOT_FOUND if the value could not be found.
1728 * @param pImage The VMDK image state.
1729 * @param pDescriptor The descriptor to fetch the value from.
1730 * @param pszKey The key to get the value from.
[59609]1731 * @param ppszValue Where to store the return value, use RTMemTmpFree to
1732 * free.
1733 */
[2742]1734static int vmdkDescBaseGetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
[59609]1735 const char *pszKey, char **ppszValue)
[2742]1736{
1737 const char *pszValue;
1738 char *pszValueUnquoted;
[97839]1739
[6291]1740 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
1741 &pszValue))
[15366]1742 return VERR_VD_VMDK_VALUE_NOT_FOUND;
[2742]1743 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
[11266]1744 if (RT_FAILURE(rc))
[2742]1745 return rc;
1746 *ppszValue = pszValueUnquoted;
1747 return rc;
1748}
[97839]1749
[2742]1750static int vmdkDescBaseSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1751 const char *pszKey, const char *pszValue)
1752{
1753 char *pszValueQuoted;
[97839]1754
[33464]1755 RTStrAPrintf(&pszValueQuoted, "\"%s\"", pszValue);
1756 if (!pszValueQuoted)
1757 return VERR_NO_STR_MEMORY;
1758 int rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey,
1759 pszValueQuoted);
[2742]1760 RTStrFree(pszValueQuoted);
1761 return rc;
1762}
[97839]1763
[6291]1764static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage,
1765 PVMDKDESCRIPTOR pDescriptor)
[2650]1766{
[62755]1767 RT_NOREF1(pImage);
[2650]1768 unsigned uEntry = pDescriptor->uFirstExtent;
1769 ssize_t cbDiff;
[97839]1770
[2650]1771 if (!uEntry)
1772 return;
[97839]1773
[2650]1774 cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
[6291]1775 /* Move everything including \0 in the entry marking the end of buffer. */
[2650]1776 memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
1777 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
1778 for (unsigned i = uEntry + 1; i <= pDescriptor->cLines; i++)
1779 {
1780 pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff;
1781 if (pDescriptor->aNextLines[i])
1782 pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1;
1783 else
1784 pDescriptor->aNextLines[i - 1] = 0;
1785 }
1786 pDescriptor->cLines--;
1787 if (pDescriptor->uFirstDDB)
1788 pDescriptor->uFirstDDB--;
[97839]1789
[2650]1790 return;
1791}
[97839]1792
[97854]1793static void vmdkDescExtRemoveByLine(PVMDKIMAGE pImage,
1794 PVMDKDESCRIPTOR pDescriptor, unsigned uLine)
1795{
1796 RT_NOREF1(pImage);
1797 unsigned uEntry = uLine;
1798 ssize_t cbDiff;
1799 if (!uEntry)
1800 return;
1801 cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
1802 /* Move everything including \0 in the entry marking the end of buffer. */
1803 memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
1804 pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
1805 for (unsigned i = uEntry; i <= pDescriptor->cLines; i++)
1806 {
1807 if (i != uEntry)
1808 pDescriptor->aLines[i - 1] = pDescriptor->aLines[i] - cbDiff;
1809 if (pDescriptor->aNextLines[i])
1810 pDescriptor->aNextLines[i - 1] = pDescriptor->aNextLines[i] - 1;
1811 else
1812 pDescriptor->aNextLines[i - 1] = 0;
1813 }
1814 pDescriptor->cLines--;
1815 if (pDescriptor->uFirstDDB)
1816 pDescriptor->uFirstDDB--;
1817 return;
1818}
1819
[2650]1820static int vmdkDescExtInsert(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1821 VMDKACCESS enmAccess, uint64_t cNominalSectors,
1822 VMDKETYPE enmType, const char *pszBasename,
1823 uint64_t uSectorOffset)
1824{
1825 static const char *apszAccess[] = { "NOACCESS", "RDONLY", "RW" };
[18566]1826 static const char *apszType[] = { "", "SPARSE", "FLAT", "ZERO", "VMFS" };
[2650]1827 char *pszTmp;
[2829]1828 unsigned uStart = pDescriptor->uFirstExtent, uLast = 0;
[2650]1829 char szExt[1024];
1830 ssize_t cbDiff;
[97839]1831
[18822]1832 Assert((unsigned)enmAccess < RT_ELEMENTS(apszAccess));
1833 Assert((unsigned)enmType < RT_ELEMENTS(apszType));
[97839]1834
[2650]1835 /* Find last entry in extent description. */
1836 while (uStart)
1837 {
1838 if (!pDescriptor->aNextLines[uStart])
1839 uLast = uStart;
1840 uStart = pDescriptor->aNextLines[uStart];
1841 }
[97839]1842
[2650]1843 if (enmType == VMDKETYPE_ZERO)
1844 {
1845 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s ", apszAccess[enmAccess],
1846 cNominalSectors, apszType[enmType]);
1847 }
[24778]1848 else if (enmType == VMDKETYPE_FLAT)
1849 {
1850 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\" %llu",
1851 apszAccess[enmAccess], cNominalSectors,
1852 apszType[enmType], pszBasename, uSectorOffset);
1853 }
[2650]1854 else
1855 {
[24778]1856 RTStrPrintf(szExt, sizeof(szExt), "%s %llu %s \"%s\"",
1857 apszAccess[enmAccess], cNominalSectors,
1858 apszType[enmType], pszBasename);
[2650]1859 }
1860 cbDiff = strlen(szExt) + 1;
[97839]1861
[2650]1862 /* Check for buffer overflow. */
1863 if ( (pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1)
1864 || ( pDescriptor->aLines[pDescriptor->cLines]
1865 - pDescriptor->aLines[0] > (ptrdiff_t)pDescriptor->cbDescAlloc - cbDiff))
[97854]1866 {
1867 if ((pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
1868 && !(pDescriptor->cLines >= VMDK_DESCRIPTOR_LINES_MAX - 1))
1869 {
1870 pImage->cbDescAlloc *= 2;
1871 pDescriptor->cbDescAlloc *= 2;
1872 }
1873 else
1874 return vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
1875 }
[97255]1876
[2650]1877 for (unsigned i = pDescriptor->cLines + 1; i > uLast + 1; i--)
1878 {
1879 pDescriptor->aLines[i] = pDescriptor->aLines[i - 1];
1880 if (pDescriptor->aNextLines[i - 1])
1881 pDescriptor->aNextLines[i] = pDescriptor->aNextLines[i - 1] + 1;
1882 else
1883 pDescriptor->aNextLines[i] = 0;
1884 }
1885 uStart = uLast + 1;
1886 pDescriptor->aNextLines[uLast] = uStart;
1887 pDescriptor->aNextLines[uStart] = 0;
1888 pDescriptor->cLines++;
1889 pszTmp = pDescriptor->aLines[uStart];
1890 memmove(pszTmp + cbDiff, pszTmp,
1891 pDescriptor->aLines[pDescriptor->cLines] - pszTmp);
1892 memcpy(pDescriptor->aLines[uStart], szExt, cbDiff);
1893 for (unsigned i = uStart + 1; i <= pDescriptor->cLines; i++)
1894 pDescriptor->aLines[i] += cbDiff;
[97839]1895
[2650]1896 /* Adjust starting line numbers of following descriptor sections. */
1897 if (uStart <= pDescriptor->uFirstDDB)
1898 pDescriptor->uFirstDDB++;
[97839]1899
[2650]1900 pDescriptor->fDirty = true;
1901 return VINF_SUCCESS;
1902}
[97839]1903
[59609]1904/**
[64272]1905 * Returns the value of the given key from the DDB as a string allocating
1906 * the necessary memory.
1907 *
1908 * @returns VBox status code.
1909 * @retval VERR_VD_VMDK_VALUE_NOT_FOUND if the value could not be found.
1910 * @param pImage The VMDK image state.
1911 * @param pDescriptor The descriptor to fetch the value from.
1912 * @param pszKey The key to get the value from.
[59609]1913 * @param ppszValue Where to store the return value, use RTMemTmpFree to
1914 * free.
1915 */
[2742]1916static int vmdkDescDDBGetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
[59609]1917 const char *pszKey, char **ppszValue)
[2742]1918{
1919 const char *pszValue;
1920 char *pszValueUnquoted;
[97839]1921
[6291]1922 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
1923 &pszValue))
[15366]1924 return VERR_VD_VMDK_VALUE_NOT_FOUND;
[2742]1925 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
[11266]1926 if (RT_FAILURE(rc))
[2742]1927 return rc;
1928 *ppszValue = pszValueUnquoted;
1929 return rc;
1930}
[97839]1931
[2358]1932static int vmdkDescDDBGetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1933 const char *pszKey, uint32_t *puValue)
1934{
1935 const char *pszValue;
1936 char *pszValueUnquoted;
[97839]1937
[6291]1938 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
1939 &pszValue))
[15366]1940 return VERR_VD_VMDK_VALUE_NOT_FOUND;
[2358]1941 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
[11266]1942 if (RT_FAILURE(rc))
[2358]1943 return rc;
1944 rc = RTStrToUInt32Ex(pszValueUnquoted, NULL, 10, puValue);
1945 RTMemTmpFree(pszValueUnquoted);
1946 return rc;
1947}
[97839]1948
[2358]1949static int vmdkDescDDBGetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1950 const char *pszKey, PRTUUID pUuid)
1951{
1952 const char *pszValue;
1953 char *pszValueUnquoted;
[97839]1954
[6291]1955 if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
1956 &pszValue))
[15366]1957 return VERR_VD_VMDK_VALUE_NOT_FOUND;
[2358]1958 int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
[11266]1959 if (RT_FAILURE(rc))
[2358]1960 return rc;
1961 rc = RTUuidFromStr(pUuid, pszValueUnquoted);
1962 RTMemTmpFree(pszValueUnquoted);
1963 return rc;
1964}
[97839]1965
[6291]1966static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1967 const char *pszKey, const char *pszVal)
[2650]1968{
[2742]1969 int rc;
[2650]1970 char *pszValQuoted;
[97839]1971
[2742]1972 if (pszVal)
1973 {
[33464]1974 RTStrAPrintf(&pszValQuoted, "\"%s\"", pszVal);
1975 if (!pszValQuoted)
1976 return VERR_NO_STR_MEMORY;
[2742]1977 }
1978 else
1979 pszValQuoted = NULL;
[6291]1980 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
1981 pszValQuoted);
[2742]1982 if (pszValQuoted)
1983 RTStrFree(pszValQuoted);
[2650]1984 return rc;
1985}
[97839]1986
[6291]1987static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
1988 const char *pszKey, PCRTUUID pUuid)
[2358]1989{
1990 char *pszUuid;
[97839]1991
[33464]1992 RTStrAPrintf(&pszUuid, "\"%RTuuid\"", pUuid);
1993 if (!pszUuid)
1994 return VERR_NO_STR_MEMORY;
1995 int rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
1996 pszUuid);
[2358]1997 RTStrFree(pszUuid);
1998 return rc;
1999}
[97839]2000
[7155]2001static int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
2002 const char *pszKey, uint32_t uValue)
[2358]2003{
2004 char *pszValue;
[97839]2005
[33464]2006 RTStrAPrintf(&pszValue, "\"%d\"", uValue);
2007 if (!pszValue)
2008 return VERR_NO_STR_MEMORY;
2009 int rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
2010 pszValue);
[2358]2011 RTStrFree(pszValue);
2012 return rc;
2013}
[97839]2014
[63798]2015/**
2016 * Splits the descriptor data into individual lines checking for correct line
2017 * endings and descriptor size.
2018 *
2019 * @returns VBox status code.
2020 * @param pImage The image instance.
2021 * @param pDesc The descriptor.
2022 * @param pszTmp The raw descriptor data from the image.
2023 */
2024static int vmdkDescSplitLines(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDesc, char *pszTmp)
[2358]2025{
[63798]2026 unsigned cLine = 0;
[2358]2027 int rc = VINF_SUCCESS;
[97839]2028
[63798]2029 while ( RT_SUCCESS(rc)
2030 && *pszTmp != '\0')
[2358]2031 {
[63798]2032 pDesc->aLines[cLine++] = pszTmp;
[2358]2033 if (cLine >= VMDK_DESCRIPTOR_LINES_MAX)
2034 {
[63799]2035 vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor too big in '%s'"), pImage->pszFilename);
2036 rc = VERR_VD_VMDK_INVALID_HEADER;
[63798]2037 break;
[2358]2038 }
[97839]2039
[63798]2040 while (*pszTmp != '\0' && *pszTmp != '\n')
[2358]2041 {
[63798]2042 if (*pszTmp == '\r')
[2358]2043 {
[63798]2044 if (*(pszTmp + 1) != '\n')
[2358]2045 {
[38469]2046 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: unsupported end of line in descriptor in '%s'"), pImage->pszFilename);
[63798]2047 break;
[2358]2048 }
2049 else
2050 {
2051 /* Get rid of CR character. */
[63798]2052 *pszTmp = '\0';
[2358]2053 }
2054 }
[63798]2055 pszTmp++;
[2358]2056 }
[97839]2057
[63799]2058 if (RT_FAILURE(rc))
2059 break;
[97839]2060
[2358]2061 /* Get rid of LF character. */
[63798]2062 if (*pszTmp == '\n')
[2358]2063 {
[63798]2064 *pszTmp = '\0';
2065 pszTmp++;
[2358]2066 }
2067 }
[97839]2068
[63798]2069 if (RT_SUCCESS(rc))
[2358]2070 {
[63798]2071 pDesc->cLines = cLine;
2072 /* Pointer right after the end of the used part of the buffer. */
2073 pDesc->aLines[cLine] = pszTmp;
[2358]2074 }
[97839]2075
[63798]2076 return rc;
2077}
[97839]2078
[63798]2079static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
2080 size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
2081{
2082 pDescriptor->cbDescAlloc = cbDescData;
2083 int rc = vmdkDescSplitLines(pImage, pDescriptor, pDescData);
2084 if (RT_SUCCESS(rc))
[2358]2085 {
[63798]2086 if ( strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile")
[70853]2087 && strcmp(pDescriptor->aLines[0], "# Disk Descriptor File")
2088 && strcmp(pDescriptor->aLines[0], "#Disk Descriptor File")
2089 && strcmp(pDescriptor->aLines[0], "#Disk DescriptorFile"))
[63798]2090 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2091 N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename);
2092 else
[2358]2093 {
[63798]2094 unsigned uLastNonEmptyLine = 0;
[97839]2095
[63798]2096 /* Initialize those, because we need to be able to reopen an image. */
2097 pDescriptor->uFirstDesc = 0;
2098 pDescriptor->uFirstExtent = 0;
2099 pDescriptor->uFirstDDB = 0;
2100 for (unsigned i = 0; i < pDescriptor->cLines; i++)
[2358]2101 {
[63798]2102 if (*pDescriptor->aLines[i] != '#' && *pDescriptor->aLines[i] != '\0')
[2358]2103 {
[63798]2104 if ( !strncmp(pDescriptor->aLines[i], "RW", 2)
2105 || !strncmp(pDescriptor->aLines[i], "RDONLY", 6)
2106 || !strncmp(pDescriptor->aLines[i], "NOACCESS", 8) )
2107 {
2108 /* An extent descriptor. */
2109 if (!pDescriptor->uFirstDesc || pDescriptor->uFirstDDB)
2110 {
2111 /* Incorrect ordering of entries. */
2112 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2113 N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
2114 break;
2115 }
2116 if (!pDescriptor->uFirstExtent)
2117 {
2118 pDescriptor->uFirstExtent = i;
2119 uLastNonEmptyLine = 0;
2120 }
2121 }
2122 else if (!strncmp(pDescriptor->aLines[i], "ddb.", 4))
2123 {
2124 /* A disk database entry. */
2125 if (!pDescriptor->uFirstDesc || !pDescriptor->uFirstExtent)
2126 {
2127 /* Incorrect ordering of entries. */
2128 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2129 N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
2130 break;
2131 }
2132 if (!pDescriptor->uFirstDDB)
2133 {
2134 pDescriptor->uFirstDDB = i;
2135 uLastNonEmptyLine = 0;
2136 }
2137 }
2138 else
2139 {
2140 /* A normal entry. */
2141 if (pDescriptor->uFirstExtent || pDescriptor->uFirstDDB)
2142 {
2143 /* Incorrect ordering of entries. */
2144 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2145 N_("VMDK: incorrect ordering of entries in descriptor in '%s'"), pImage->pszFilename);
2146 break;
2147 }
2148 if (!pDescriptor->uFirstDesc)
2149 {
2150 pDescriptor->uFirstDesc = i;
2151 uLastNonEmptyLine = 0;
2152 }
2153 }
2154 if (uLastNonEmptyLine)
2155 pDescriptor->aNextLines[uLastNonEmptyLine] = i;
2156 uLastNonEmptyLine = i;
[2358]2157 }
2158 }
2159 }
2160 }
[97839]2161
[2358]2162 return rc;
2163}
[97839]2164
[6291]2165static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage,
[32536]2166 PCVDGEOMETRY pPCHSGeometry)
[2650]2167{
[6291]2168 int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2169 VMDK_DDB_GEO_PCHS_CYLINDERS,
2170 pPCHSGeometry->cCylinders);
[11266]2171 if (RT_FAILURE(rc))
[6291]2172 return rc;
2173 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2174 VMDK_DDB_GEO_PCHS_HEADS,
2175 pPCHSGeometry->cHeads);
[11266]2176 if (RT_FAILURE(rc))
[6291]2177 return rc;
2178 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2179 VMDK_DDB_GEO_PCHS_SECTORS,
2180 pPCHSGeometry->cSectors);
2181 return rc;
2182}
[97839]2183
[6291]2184static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage,
[32536]2185 PCVDGEOMETRY pLCHSGeometry)
[6291]2186{
2187 int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2188 VMDK_DDB_GEO_LCHS_CYLINDERS,
2189 pLCHSGeometry->cCylinders);
[11266]2190 if (RT_FAILURE(rc))
[6291]2191 return rc;
2192 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2193 VMDK_DDB_GEO_LCHS_HEADS,
[97839]2194
[6291]2195 pLCHSGeometry->cHeads);
[11266]2196 if (RT_FAILURE(rc))
[6291]2197 return rc;
2198 rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
2199 VMDK_DDB_GEO_LCHS_SECTORS,
2200 pLCHSGeometry->cSectors);
2201 return rc;
2202}
[97839]2203
[6291]2204static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData,
2205 size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
2206{
[2650]2207 pDescriptor->uFirstDesc = 0;
2208 pDescriptor->uFirstExtent = 0;
2209 pDescriptor->uFirstDDB = 0;
2210 pDescriptor->cLines = 0;
2211 pDescriptor->cbDescAlloc = cbDescData;
2212 pDescriptor->fDirty = false;
2213 pDescriptor->aLines[pDescriptor->cLines] = pDescData;
2214 memset(pDescriptor->aNextLines, '\0', sizeof(pDescriptor->aNextLines));
[97839]2215
[63798]2216 int rc = vmdkDescInitStr(pImage, pDescriptor, "# Disk DescriptorFile");
2217 if (RT_SUCCESS(rc))
2218 rc = vmdkDescInitStr(pImage, pDescriptor, "version=1");
2219 if (RT_SUCCESS(rc))
2220 {
2221 pDescriptor->uFirstDesc = pDescriptor->cLines - 1;
2222 rc = vmdkDescInitStr(pImage, pDescriptor, "");
2223 }
2224 if (RT_SUCCESS(rc))
2225 rc = vmdkDescInitStr(pImage, pDescriptor, "# Extent description");
2226 if (RT_SUCCESS(rc))
2227 rc = vmdkDescInitStr(pImage, pDescriptor, "NOACCESS 0 ZERO ");
2228 if (RT_SUCCESS(rc))
2229 {
2230 pDescriptor->uFirstExtent = pDescriptor->cLines - 1;
2231 rc = vmdkDescInitStr(pImage, pDescriptor, "");
2232 }
2233 if (RT_SUCCESS(rc))
2234 {
2235 /* The trailing space is created by VMware, too. */
2236 rc = vmdkDescInitStr(pImage, pDescriptor, "# The disk Data Base ");
2237 }
2238 if (RT_SUCCESS(rc))
2239 rc = vmdkDescInitStr(pImage, pDescriptor, "#DDB");
2240 if (RT_SUCCESS(rc))
2241 rc = vmdkDescInitStr(pImage, pDescriptor, "");
2242 if (RT_SUCCESS(rc))
2243 rc = vmdkDescInitStr(pImage, pDescriptor, "ddb.virtualHWVersion = \"4\"");
2244 if (RT_SUCCESS(rc))
2245 {
2246 pDescriptor->uFirstDDB = pDescriptor->cLines - 1;
[97839]2247
[63798]2248 /* Now that the framework is in place, use the normal functions to insert
2249 * the remaining keys. */
2250 char szBuf[9];
2251 RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32());
2252 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
2253 "CID", szBuf);
2254 }
2255 if (RT_SUCCESS(rc))
2256 rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
2257 "parentCID", "ffffffff");
2258 if (RT_SUCCESS(rc))
2259 rc = vmdkDescDDBSetStr(pImage, pDescriptor, "ddb.adapterType", "ide");
[97839]2260
[2650]2261 return rc;
2262}
[97839]2263
[63798]2264static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
[2358]2265{
2266 int rc;
2267 unsigned cExtents;
2268 unsigned uLine;
[25823]2269 unsigned i;
[97839]2270
[6291]2271 rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData,
2272 &pImage->Descriptor);
[11266]2273 if (RT_FAILURE(rc))
[2358]2274 return rc;
[97839]2275
[2358]2276 /* Check version, must be 1. */
2277 uint32_t uVersion;
2278 rc = vmdkDescBaseGetU32(&pImage->Descriptor, "version", &uVersion);
[11266]2279 if (RT_FAILURE(rc))
[38469]2280 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error finding key 'version' in descriptor in '%s'"), pImage->pszFilename);
[2358]2281 if (uVersion != 1)
[38469]2282 return vdIfError(pImage->pIfError, VERR_VD_VMDK_UNSUPPORTED_VERSION, RT_SRC_POS, N_("VMDK: unsupported format version in descriptor in '%s'"), pImage->pszFilename);
[97839]2283
[2742]2284 /* Get image creation type and determine image flags. */
[59609]2285 char *pszCreateType = NULL; /* initialized to make gcc shut up */
[2742]2286 rc = vmdkDescBaseGetStr(pImage, &pImage->Descriptor, "createType",
2287 &pszCreateType);
[11266]2288 if (RT_FAILURE(rc))
[38469]2289 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot get image type from descriptor in '%s'"), pImage->pszFilename);
[2742]2290 if ( !strcmp(pszCreateType, "twoGbMaxExtentSparse")
2291 || !strcmp(pszCreateType, "twoGbMaxExtentFlat"))
[17970]2292 pImage->uImageFlags |= VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
[16827]2293 else if ( !strcmp(pszCreateType, "partitionedDevice")
2294 || !strcmp(pszCreateType, "fullDevice"))
[17970]2295 pImage->uImageFlags |= VD_VMDK_IMAGE_FLAGS_RAWDISK;
[16827]2296 else if (!strcmp(pszCreateType, "streamOptimized"))
[17970]2297 pImage->uImageFlags |= VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED;
[18566]2298 else if (!strcmp(pszCreateType, "vmfs"))
2299 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_ESX;
[59609]2300 RTMemTmpFree(pszCreateType);
[97839]2301
[2358]2302 /* Count the number of extent config entries. */
2303 for (uLine = pImage->Descriptor.uFirstExtent, cExtents = 0;
2304 uLine != 0;
2305 uLine = pImage->Descriptor.aNextLines[uLine], cExtents++)
2306 /* nothing */;
[97839]2307
[2358]2308 if (!pImage->pDescData && cExtents != 1)
2309 {
2310 /* Monolithic image, must have only one extent (already opened). */
[38469]2311 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);
[2358]2312 }
[97839]2313
[2358]2314 if (pImage->pDescData)
2315 {
2316 /* Non-monolithic image, extents need to be allocated. */
2317 rc = vmdkCreateExtents(pImage, cExtents);
[11266]2318 if (RT_FAILURE(rc))
[2358]2319 return rc;
2320 }
[97839]2321
[25823]2322 for (i = 0, uLine = pImage->Descriptor.uFirstExtent;
[2358]2323 i < cExtents; i++, uLine = pImage->Descriptor.aNextLines[uLine])
2324 {
2325 char *pszLine = pImage->Descriptor.aLines[uLine];
[97839]2326
[2358]2327 /* Access type of the extent. */
2328 if (!strncmp(pszLine, "RW", 2))
2329 {
2330 pImage->pExtents[i].enmAccess = VMDKACCESS_READWRITE;
2331 pszLine += 2;
2332 }
2333 else if (!strncmp(pszLine, "RDONLY", 6))
2334 {
2335 pImage->pExtents[i].enmAccess = VMDKACCESS_READONLY;
2336 pszLine += 6;
2337 }
2338 else if (!strncmp(pszLine, "NOACCESS", 8))
2339 {
2340 pImage->pExtents[i].enmAccess = VMDKACCESS_NOACCESS;
2341 pszLine += 8;
2342 }
2343 else
[38469]2344 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[2358]2345 if (*pszLine++ != ' ')
[38469]2346 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[97839]2347
[2358]2348 /* Nominal size of the extent. */
2349 rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
2350 &pImage->pExtents[i].cNominalSectors);
[11266]2351 if (RT_FAILURE(rc))
[38469]2352 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[2358]2353 if (*pszLine++ != ' ')
[38469]2354 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[97839]2355
[2358]2356 /* Type of the extent. */
2357 if (!strncmp(pszLine, "SPARSE", 6))
2358 {
2359 pImage->pExtents[i].enmType = VMDKETYPE_HOSTED_SPARSE;
2360 pszLine += 6;
2361 }
2362 else if (!strncmp(pszLine, "FLAT", 4))
2363 {
2364 pImage->pExtents[i].enmType = VMDKETYPE_FLAT;
2365 pszLine += 4;
2366 }
2367 else if (!strncmp(pszLine, "ZERO", 4))
2368 {
2369 pImage->pExtents[i].enmType = VMDKETYPE_ZERO;
2370 pszLine += 4;
2371 }
[18566]2372 else if (!strncmp(pszLine, "VMFS", 4))
2373 {
2374 pImage->pExtents[i].enmType = VMDKETYPE_VMFS;
2375 pszLine += 4;
2376 }
[2358]2377 else
[38469]2378 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[97839]2379
[2358]2380 if (pImage->pExtents[i].enmType == VMDKETYPE_ZERO)
2381 {
2382 /* This one has no basename or offset. */
2383 if (*pszLine == ' ')
2384 pszLine++;
2385 if (*pszLine != '\0')
[38469]2386 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[2358]2387 pImage->pExtents[i].pszBasename = NULL;
2388 }
2389 else
2390 {
2391 /* All other extent types have basename and optional offset. */
2392 if (*pszLine++ != ' ')
[38469]2393 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[97839]2394
[2358]2395 /* Basename of the image. Surrounded by quotes. */
[2650]2396 char *pszBasename;
2397 rc = vmdkStringUnquote(pImage, pszLine, &pszBasename, &pszLine);
[11266]2398 if (RT_FAILURE(rc))
[2358]2399 return rc;
[2650]2400 pImage->pExtents[i].pszBasename = pszBasename;
[2358]2401 if (*pszLine == ' ')
2402 {
2403 pszLine++;
2404 if (*pszLine != '\0')
2405 {
2406 /* Optional offset in extent specified. */
2407 rc = RTStrToUInt64Ex(pszLine, &pszLine, 10,
2408 &pImage->pExtents[i].uSectorOffset);
[11266]2409 if (RT_FAILURE(rc))
[38469]2410 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[2358]2411 }
2412 }
[97839]2413
[2358]2414 if (*pszLine != '\0')
[38469]2415 return vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: parse error in extent description in '%s'"), pImage->pszFilename);
[2358]2416 }
2417 }
[97839]2418
[6291]2419 /* Determine PCHS geometry (autogenerate if necessary). */
[2358]2420 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
[6291]2421 VMDK_DDB_GEO_PCHS_CYLINDERS,
2422 &pImage->PCHSGeometry.cCylinders);
[15366]2423 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[6291]2424 pImage->PCHSGeometry.cCylinders = 0;
[11266]2425 else if (RT_FAILURE(rc))
[38469]2426 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
[2358]2427 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
[6291]2428 VMDK_DDB_GEO_PCHS_HEADS,
2429 &pImage->PCHSGeometry.cHeads);
[15366]2430 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[6291]2431 pImage->PCHSGeometry.cHeads = 0;
[11266]2432 else if (RT_FAILURE(rc))
[38469]2433 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
[2358]2434 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
[6291]2435 VMDK_DDB_GEO_PCHS_SECTORS,
2436 &pImage->PCHSGeometry.cSectors);
[15366]2437 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[6291]2438 pImage->PCHSGeometry.cSectors = 0;
[11266]2439 else if (RT_FAILURE(rc))
[38469]2440 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
[6291]2441 if ( pImage->PCHSGeometry.cCylinders == 0
2442 || pImage->PCHSGeometry.cHeads == 0
2443 || pImage->PCHSGeometry.cHeads > 16
2444 || pImage->PCHSGeometry.cSectors == 0
2445 || pImage->PCHSGeometry.cSectors > 63)
2446 {
2447 /* Mark PCHS geometry as not yet valid (can't do the calculation here
2448 * as the total image size isn't known yet). */
2449 pImage->PCHSGeometry.cCylinders = 0;
2450 pImage->PCHSGeometry.cHeads = 16;
2451 pImage->PCHSGeometry.cSectors = 63;
2452 }
[97839]2453
[6291]2454 /* Determine LCHS geometry (set to 0 if not specified). */
2455 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2456 VMDK_DDB_GEO_LCHS_CYLINDERS,
2457 &pImage->LCHSGeometry.cCylinders);
[15366]2458 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[6291]2459 pImage->LCHSGeometry.cCylinders = 0;
[11266]2460 else if (RT_FAILURE(rc))
[38469]2461 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
[6291]2462 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2463 VMDK_DDB_GEO_LCHS_HEADS,
2464 &pImage->LCHSGeometry.cHeads);
[15366]2465 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[6291]2466 pImage->LCHSGeometry.cHeads = 0;
[11266]2467 else if (RT_FAILURE(rc))
[38469]2468 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
[6291]2469 rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
2470 VMDK_DDB_GEO_LCHS_SECTORS,
2471 &pImage->LCHSGeometry.cSectors);
[15366]2472 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[6291]2473 pImage->LCHSGeometry.cSectors = 0;
[11266]2474 else if (RT_FAILURE(rc))
[38469]2475 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
[6291]2476 if ( pImage->LCHSGeometry.cCylinders == 0
2477 || pImage->LCHSGeometry.cHeads == 0
2478 || pImage->LCHSGeometry.cSectors == 0)
2479 {
2480 pImage->LCHSGeometry.cCylinders = 0;
2481 pImage->LCHSGeometry.cHeads = 0;
2482 pImage->LCHSGeometry.cSectors = 0;
2483 }
[97839]2484
[2358]2485 /* Get image UUID. */
[7155]2486 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_IMAGE_UUID,
[2358]2487 &pImage->ImageUuid);
[15366]2488 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[2358]2489 {
2490 /* Image without UUID. Probably created by VMware and not yet used
2491 * by VirtualBox. Can only be added for images opened in read/write
2492 * mode, so don't bother producing a sensible UUID otherwise. */
2493 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2494 RTUuidClear(&pImage->ImageUuid);
2495 else
2496 {
2497 rc = RTUuidCreate(&pImage->ImageUuid);
[11266]2498 if (RT_FAILURE(rc))
[2358]2499 return rc;
2500 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
[7155]2501 VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
[11266]2502 if (RT_FAILURE(rc))
[38469]2503 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in descriptor in '%s'"), pImage->pszFilename);
[2358]2504 }
2505 }
[11266]2506 else if (RT_FAILURE(rc))
[2358]2507 return rc;
[97839]2508
[2358]2509 /* Get image modification UUID. */
[6291]2510 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
[7155]2511 VMDK_DDB_MODIFICATION_UUID,
[2358]2512 &pImage->ModificationUuid);
[15366]2513 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[2358]2514 {
2515 /* Image without UUID. Probably created by VMware and not yet used
2516 * by VirtualBox. Can only be added for images opened in read/write
2517 * mode, so don't bother producing a sensible UUID otherwise. */
2518 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2519 RTUuidClear(&pImage->ModificationUuid);
2520 else
2521 {
2522 rc = RTUuidCreate(&pImage->ModificationUuid);
[11266]2523 if (RT_FAILURE(rc))
[2358]2524 return rc;
2525 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
[7155]2526 VMDK_DDB_MODIFICATION_UUID,
[6291]2527 &pImage->ModificationUuid);
[11266]2528 if (RT_FAILURE(rc))
[38469]2529 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename);
[2358]2530 }
2531 }
[11266]2532 else if (RT_FAILURE(rc))
[2358]2533 return rc;
[97839]2534
[2358]2535 /* Get UUID of parent image. */
[7155]2536 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, VMDK_DDB_PARENT_UUID,
[2358]2537 &pImage->ParentUuid);
[15366]2538 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[2358]2539 {
2540 /* Image without UUID. Probably created by VMware and not yet used
2541 * by VirtualBox. Can only be added for images opened in read/write
2542 * mode, so don't bother producing a sensible UUID otherwise. */
2543 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2544 RTUuidClear(&pImage->ParentUuid);
2545 else
2546 {
2547 rc = RTUuidClear(&pImage->ParentUuid);
[11266]2548 if (RT_FAILURE(rc))
[2358]2549 return rc;
2550 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
[7155]2551 VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
[11266]2552 if (RT_FAILURE(rc))
[38469]2553 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing parent UUID in descriptor in '%s'"), pImage->pszFilename);
[2358]2554 }
2555 }
[11266]2556 else if (RT_FAILURE(rc))
[2358]2557 return rc;
[97839]2558
[7155]2559 /* Get parent image modification UUID. */
2560 rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
2561 VMDK_DDB_PARENT_MODIFICATION_UUID,
2562 &pImage->ParentModificationUuid);
[15366]2563 if (rc == VERR_VD_VMDK_VALUE_NOT_FOUND)
[7155]2564 {
2565 /* Image without UUID. Probably created by VMware and not yet used
2566 * by VirtualBox. Can only be added for images opened in read/write
2567 * mode, so don't bother producing a sensible UUID otherwise. */
2568 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2569 RTUuidClear(&pImage->ParentModificationUuid);
2570 else
2571 {
[36173]2572 RTUuidClear(&pImage->ParentModificationUuid);
[7155]2573 rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
2574 VMDK_DDB_PARENT_MODIFICATION_UUID,
2575 &pImage->ParentModificationUuid);
[11266]2576 if (RT_FAILURE(rc))
[38469]2577 return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in descriptor in '%s'"), pImage->pszFilename);
[7155]2578 }
2579 }
[11266]2580 else if (RT_FAILURE(rc))
[7155]2581 return rc;
[97839]2582
[2358]2583 return VINF_SUCCESS;
2584}
[97839]2585
[7155]2586/**
[33480]2587 * Internal : Prepares the descriptor to write to the image.
[7155]2588 */
[33480]2589static int vmdkDescriptorPrepare(PVMDKIMAGE pImage, uint64_t cbLimit,
2590 void **ppvData, size_t *pcbData)
[2358]2591{
2592 int rc = VINF_SUCCESS;
[97839]2593
[27531]2594 /*
2595 * Allocate temporary descriptor buffer.
2596 * In case there is no limit allocate a default
2597 * and increase if required.
2598 */
2599 size_t cbDescriptor = cbLimit ? cbLimit : 4 * _1K;
2600 char *pszDescriptor = (char *)RTMemAllocZ(cbDescriptor);
[48851]2601 size_t offDescriptor = 0;
[97839]2602
[27531]2603 if (!pszDescriptor)
2604 return VERR_NO_MEMORY;
[97839]2605
[2358]2606 for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
2607 {
2608 const char *psz = pImage->Descriptor.aLines[i];
2609 size_t cb = strlen(psz);
[97839]2610
[27531]2611 /*
2612 * Increase the descriptor if there is no limit and
2613 * there is not enough room left for this line.
2614 */
2615 if (offDescriptor + cb + 1 > cbDescriptor)
2616 {
2617 if (cbLimit)
2618 {
[38469]2619 rc = vdIfError(pImage->pIfError, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
[27531]2620 break;
2621 }
2622 else
2623 {
2624 char *pszDescriptorNew = NULL;
2625 LogFlow(("Increasing descriptor cache\n"));
[97839]2626
[27533]2627 pszDescriptorNew = (char *)RTMemRealloc(pszDescriptor, cbDescriptor + cb + 4 * _1K);
[27531]2628 if (!pszDescriptorNew)
2629 {
2630 rc = VERR_NO_MEMORY;
2631 break;
2632 }
[33480]2633 pszDescriptor = pszDescriptorNew;
[27531]2634 cbDescriptor += cb + 4 * _1K;
2635 }
2636 }
[97839]2637
[27477]2638 if (cb > 0)
2639 {
[27531]2640 memcpy(pszDescriptor + offDescriptor, psz, cb);
2641 offDescriptor += cb;
[27477]2642 }
[97839]2643
[27531]2644 memcpy(pszDescriptor + offDescriptor, "\n", 1);
2645 offDescriptor++;
[2358]2646 }
[97839]2647
[27531]2648 if (RT_SUCCESS(rc))
[2358]2649 {
[33480]2650 *ppvData = pszDescriptor;
2651 *pcbData = offDescriptor;
2652 }
[33943]2653 else if (pszDescriptor)
2654 RTMemFree(pszDescriptor);
[97839]2655
[33480]2656 return rc;
2657}
[97839]2658
[33480]2659/**
2660 * Internal: write/update the descriptor part of the image.
2661 */
[44252]2662static int vmdkWriteDescriptor(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
[33480]2663{
2664 int rc = VINF_SUCCESS;
2665 uint64_t cbLimit;
2666 uint64_t uOffset;
2667 PVMDKFILE pDescFile;
[44252]2668 void *pvDescriptor = NULL;
[33480]2669 size_t cbDescriptor;
[97839]2670
[33480]2671 if (pImage->pDescData)
2672 {
2673 /* Separate descriptor file. */
2674 uOffset = 0;
2675 cbLimit = 0;
2676 pDescFile = pImage->pFile;
2677 }
2678 else
2679 {
2680 /* Embedded descriptor file. */
2681 uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector);
2682 cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
2683 pDescFile = pImage->pExtents[0].pFile;
2684 }
2685 /* Bail out if there is no file to write to. */
2686 if (pDescFile == NULL)
2687 return VERR_INVALID_PARAMETER;
[97839]2688
[33480]2689 rc = vmdkDescriptorPrepare(pImage, cbLimit, &pvDescriptor, &cbDescriptor);
2690 if (RT_SUCCESS(rc))
2691 {
[44233]2692 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pDescFile->pStorage,
2693 uOffset, pvDescriptor,
2694 cbLimit ? cbLimit : cbDescriptor,
2695 pIoCtx, NULL, NULL);
[32892]2696 if ( RT_FAILURE(rc)
2697 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
[38469]2698 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
[28620]2699 }
[97839]2700
[28620]2701 if (RT_SUCCESS(rc) && !cbLimit)
2702 {
[38469]2703 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pDescFile->pStorage, cbDescriptor);
[28620]2704 if (RT_FAILURE(rc))
[38469]2705 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
[28620]2706 }
[97839]2707
[28620]2708 if (RT_SUCCESS(rc))
2709 pImage->Descriptor.fDirty = false;
[97839]2710
[44252]2711 if (pvDescriptor)
2712 RTMemFree(pvDescriptor);
[28620]2713 return rc;
[97839]2714
[28620]2715}
[97839]2716
[28620]2717/**
[16827]2718 * Internal: validate the consistency check values in a binary header.
2719 */
2720static int vmdkValidateHeader(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, const SparseExtentHeader *pHeader)
2721{
2722 int rc = VINF_SUCCESS;
2723 if (RT_LE2H_U32(pHeader->magicNumber) != VMDK_SPARSE_MAGICNUMBER)
2724 {
[38469]2725 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: incorrect magic in sparse extent header in '%s'"), pExtent->pszFullname);
[16827]2726 return rc;
2727 }
2728 if (RT_LE2H_U32(pHeader->version) != 1 && RT_LE2H_U32(pHeader->version) != 3)
2729 {
[38469]2730 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);
[16827]2731 return rc;
2732 }
2733 if ( (RT_LE2H_U32(pHeader->flags) & 1)
2734 && ( pHeader->singleEndLineChar != '\n'
2735 || pHeader->nonEndLineChar != ' '
2736 || pHeader->doubleEndLineChar1 != '\r'
2737 || pHeader->doubleEndLineChar2 != '\n') )
2738 {
[38469]2739 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: corrupted by CR/LF translation in '%s'"), pExtent->pszFullname);
[16827]2740 return rc;
2741 }
[77773]2742 if (RT_LE2H_U64(pHeader->descriptorSize) > VMDK_SPARSE_DESCRIPTOR_SIZE_MAX)
2743 {
2744 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS, N_("VMDK: descriptor size out of bounds (%llu vs %llu) '%s'"),
2745 pExtent->pszFullname, RT_LE2H_U64(pHeader->descriptorSize), VMDK_SPARSE_DESCRIPTOR_SIZE_MAX);
2746 return rc;
2747 }
[16827]2748 return rc;
2749}
[97839]2750
[16827]2751/**
[12306]2752 * Internal: read metadata belonging to an extent with binary header, i.e.
2753 * as found in monolithic files.
[7155]2754 */
[33182]2755static int vmdkReadBinaryMetaExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
2756 bool fMagicAlreadyRead)
[2358]2757{
2758 SparseExtentHeader Header;
[33182]2759 int rc;
[97839]2760
[33191]2761 if (!fMagicAlreadyRead)
[38469]2762 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage, 0,
[44233]2763 &Header, sizeof(Header));
[33182]2764 else
2765 {
2766 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
[38469]2767 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
[73097]2768 RT_UOFFSETOF(SparseExtentHeader, version),
[38469]2769 &Header.version,
2770 sizeof(Header)
[73097]2771 - RT_UOFFSETOF(SparseExtentHeader, version));
[33182]2772 }
[97839]2773
[63798]2774 if (RT_SUCCESS(rc))
[33088]2775 {
[63798]2776 rc = vmdkValidateHeader(pImage, pExtent, &Header);
2777 if (RT_SUCCESS(rc))
[33182]2778 {
[63798]2779 uint64_t cbFile = 0;
[97839]2780
[63798]2781 if ( (RT_LE2H_U32(Header.flags) & RT_BIT(17))
2782 && RT_LE2H_U64(Header.gdOffset) == VMDK_GD_AT_END)
2783 pExtent->fFooter = true;
[97839]2784
[63798]2785 if ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2786 || ( pExtent->fFooter
2787 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)))
2788 {
2789 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbFile);
2790 if (RT_FAILURE(rc))
2791 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: cannot get size of '%s'"), pExtent->pszFullname);
2792 }
[97839]2793
[63798]2794 if (RT_SUCCESS(rc))
2795 {
2796 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
2797 pExtent->uAppendPosition = RT_ALIGN_64(cbFile, 512);
[97839]2798
[63798]2799 if ( pExtent->fFooter
2800 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2801 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)))
2802 {
2803 /* Read the footer, which comes before the end-of-stream marker. */
2804 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pExtent->pFile->pStorage,
2805 cbFile - 2*512, &Header,
2806 sizeof(Header));
2807 if (RT_FAILURE(rc))
2808 {
2809 vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading extent footer in '%s'"), pExtent->pszFullname);
2810 rc = VERR_VD_VMDK_INVALID_HEADER;
2811 }
[97839]2812
[63798]2813 if (RT_SUCCESS(rc))
2814 rc = vmdkValidateHeader(pImage, pExtent, &Header);
2815 /* Prohibit any writes to this extent. */
2816 pExtent->uAppendPosition = 0;
2817 }
[97839]2818
[63798]2819 if (RT_SUCCESS(rc))
2820 {
2821 pExtent->uVersion = RT_LE2H_U32(Header.version);
2822 pExtent->enmType = VMDKETYPE_HOSTED_SPARSE; /* Just dummy value, changed later. */
2823 pExtent->cSectors = RT_LE2H_U64(Header.capacity);
2824 pExtent->cSectorsPerGrain = RT_LE2H_U64(Header.grainSize);
2825 pExtent->uDescriptorSector = RT_LE2H_U64(Header.descriptorOffset);
2826 pExtent->cDescriptorSectors = RT_LE2H_U64(Header.descriptorSize);
2827 pExtent->cGTEntries = RT_LE2H_U32(Header.numGTEsPerGT);
2828 pExtent->cOverheadSectors = RT_LE2H_U64(Header.overHead);
2829 pExtent->fUncleanShutdown = !!Header.uncleanShutdown;
2830 pExtent->uCompression = RT_LE2H_U16(Header.compressAlgorithm);
2831 if (RT_LE2H_U32(Header.flags) & RT_BIT(1))
2832 {
2833 pExtent->uSectorRGD = RT_LE2H_U64(Header.rgdOffset);
2834 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
2835 }
2836 else
2837 {
2838 pExtent->uSectorGD = RT_LE2H_U64(Header.gdOffset);
2839 pExtent->uSectorRGD = 0;
2840 }
[97839]2841
[63798]2842 if (pExtent->uDescriptorSector && !pExtent->cDescriptorSectors)
2843 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2844 N_("VMDK: inconsistent embedded descriptor config in '%s'"), pExtent->pszFullname);
[97839]2845
[63798]2846 if ( RT_SUCCESS(rc)
2847 && ( pExtent->uSectorGD == VMDK_GD_AT_END
2848 || pExtent->uSectorRGD == VMDK_GD_AT_END)
2849 && ( !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2850 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)))
2851 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2852 N_("VMDK: cannot resolve grain directory offset in '%s'"), pExtent->pszFullname);
[97839]2853
[63798]2854 if (RT_SUCCESS(rc))
2855 {
2856 uint64_t cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
2857 if (!cSectorsPerGDE || cSectorsPerGDE > UINT32_MAX)
2858 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2859 N_("VMDK: incorrect grain directory size in '%s'"), pExtent->pszFullname);
2860 else
2861 {
2862 pExtent->cSectorsPerGDE = cSectorsPerGDE;
2863 pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
[97839]2864
[63798]2865 /* Fix up the number of descriptor sectors, as some flat images have
2866 * really just one, and this causes failures when inserting the UUID
2867 * values and other extra information. */
2868 if (pExtent->cDescriptorSectors != 0 && pExtent->cDescriptorSectors < 4)
2869 {
2870 /* Do it the easy way - just fix it for flat images which have no
2871 * other complicated metadata which needs space too. */
2872 if ( pExtent->uDescriptorSector + 4 < pExtent->cOverheadSectors
2873 && pExtent->cGTEntries * pExtent->cGDEntries == 0)
2874 pExtent->cDescriptorSectors = 4;
2875 }
2876 }
2877 }
2878 }
2879 }
[16827]2880 }
[15366]2881 }
[2358]2882 else
2883 {
[63798]2884 vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error reading extent header in '%s'"), pExtent->pszFullname);
2885 rc = VERR_VD_VMDK_INVALID_HEADER;
[2358]2886 }
[97839]2887
[12306]2888 if (RT_FAILURE(rc))
2889 vmdkFreeExtentData(pImage, pExtent, false);
[97839]2890
[12306]2891 return rc;
2892}
[97839]2893
[12306]2894/**
2895 * Internal: read additional metadata belonging to an extent. For those
2896 * extents which have no additional metadata just verify the information.
2897 */
2898static int vmdkReadMetaExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
2899{
2900 int rc = VINF_SUCCESS;
[97839]2901
[33182]2902/* disabled the check as there are too many truncated vmdk images out there */
2903#ifdef VBOX_WITH_VMDK_STRICT_SIZE_CHECK
[12306]2904 uint64_t cbExtentSize;
2905 /* The image must be a multiple of a sector in size and contain the data
2906 * area (flat images only). If not, it means the image is at least
2907 * truncated, or even seriously garbled. */
[38469]2908 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pExtent->pFile->pStorage, &cbExtentSize);
[12306]2909 if (RT_FAILURE(rc))
[38469]2910 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
[63798]2911 else if ( cbExtentSize != RT_ALIGN_64(cbExtentSize, 512)
[12306]2912 && (pExtent->enmType != VMDKETYPE_FLAT || pExtent->cNominalSectors + pExtent->uSectorOffset > VMDK_BYTE2SECTOR(cbExtentSize)))
[63798]2913 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2914 N_("VMDK: file size is not a multiple of 512 in '%s', file is truncated or otherwise garbled"), pExtent->pszFullname);
[12367]2915#endif /* VBOX_WITH_VMDK_STRICT_SIZE_CHECK */
[63798]2916 if ( RT_SUCCESS(rc)
2917 && pExtent->enmType == VMDKETYPE_HOSTED_SPARSE)
[12306]2918 {
[63798]2919 /* The spec says that this must be a power of two and greater than 8,
2920 * but probably they meant not less than 8. */
2921 if ( (pExtent->cSectorsPerGrain & (pExtent->cSectorsPerGrain - 1))
2922 || pExtent->cSectorsPerGrain < 8)
2923 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2924 N_("VMDK: invalid extent grain size %u in '%s'"), pExtent->cSectorsPerGrain, pExtent->pszFullname);
2925 else
2926 {
2927 /* This code requires that a grain table must hold a power of two multiple
2928 * of the number of entries per GT cache entry. */
2929 if ( (pExtent->cGTEntries & (pExtent->cGTEntries - 1))
2930 || pExtent->cGTEntries < VMDK_GT_CACHELINE_SIZE)
2931 rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
2932 N_("VMDK: grain table cache size problem in '%s'"), pExtent->pszFullname);
2933 else
2934 {
2935 rc = vmdkAllocStreamBuffers(pImage, pExtent);
2936 if (RT_SUCCESS(rc))
2937 {
2938 /* Prohibit any writes to this streamOptimized extent. */
2939 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
2940 pExtent->uAppendPosition = 0;
[97839]2941
[63798]2942 if ( !(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
2943 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
2944 || !(pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
2945 rc = vmdkReadGrainDirectory(pImage, pExtent);
2946 else
2947 {
2948 pExtent->uGrainSectorAbs = pExtent->cOverheadSectors;
2949 pExtent->cbGrainStreamRead = 0;
2950 }
2951 }
2952 }
2953 }
[12306]2954 }
[97839]2955
[33182]2956 if (RT_FAILURE(rc))
[7576]2957 vmdkFreeExtentData(pImage, pExtent, false);
[97839]2958
[2358]2959 return rc;
2960}
[97839]2961
[7155]2962/**
2963 * Internal: write/update the metadata for a sparse extent.
2964 */
[32536]2965static int vmdkWriteMetaSparseExtent(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
[44252]2966 uint64_t uOffset, PVDIOCTX pIoCtx)
[2358]2967{
2968 SparseExtentHeader Header;
[97839]2969
[2358]2970 memset(&Header, '\0', sizeof(Header));
2971 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
[18067]2972 Header.version = RT_H2LE_U32(pExtent->uVersion);
[16827]2973 Header.flags = RT_H2LE_U32(RT_BIT(0));
2974 if (pExtent->pRGD)
2975 Header.flags |= RT_H2LE_U32(RT_BIT(1));
[32536]2976 if (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
[16827]2977 Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17));
[2358]2978 Header.capacity = RT_H2LE_U64(pExtent->cSectors);
2979 Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
2980 Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector);
2981 Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
2982 Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
[18067]2983 if (pExtent->fFooter && uOffset == 0)
[2358]2984 {
[18067]2985 if (pExtent->pRGD)
2986 {
2987 Assert(pExtent->uSectorRGD);
2988 Header.rgdOffset = RT_H2LE_U64(VMDK_GD_AT_END);