VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 weeks ago

Copyright year updates by scm.

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