VirtualBox

source: vbox/trunk/src/VBox/Storage/Parallels.cpp@ 77807

Last change on this file since 77807 was 77699, checked in by vboxsync, 6 years ago

Storage/VHD,Parallels: Plug two small memory leaks when opening an image fails at a particular stage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.4 KB
RevLine 
[21371]1/* $Id: Parallels.cpp 77699 2019-03-13 23:22:08Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
[76553]8 * Copyright (C) 2006-2019 Oracle Corporation
[21371]9 *
[21373]10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
[21371]17 */
18
[32536]19#define LOG_GROUP LOG_GROUP_VD_PARALLELS
[33567]20#include <VBox/vd-plugin.h>
[21371]21#include <VBox/err.h>
22
23#include <VBox/log.h>
24#include <iprt/assert.h>
[32536]25#include <iprt/mem.h>
[21371]26#include <iprt/uuid.h>
27#include <iprt/path.h>
28#include <iprt/string.h>
[40948]29#include <iprt/asm.h>
[21371]30
[50988]31#include "VDBackends.h"
32
[21371]33#define PARALLELS_HEADER_MAGIC "WithoutFreeSpace"
34#define PARALLELS_DISK_VERSION 2
35
36/** The header of the parallels disk. */
37#pragma pack(1)
38typedef struct ParallelsHeader
39{
40 /** The magic header to identify a parallels hdd image. */
41 char HeaderIdentifier[16];
42 /** The version of the disk image. */
43 uint32_t uVersion;
44 /** The number of heads the hdd has. */
45 uint32_t cHeads;
46 /** Number of cylinders. */
47 uint32_t cCylinders;
48 /** Number of sectors per track. */
49 uint32_t cSectorsPerTrack;
50 /** Number of entries in the allocation bitmap. */
51 uint32_t cEntriesInAllocationBitmap;
52 /** Total number of sectors. */
53 uint32_t cSectors;
54 /** Padding. */
55 char Padding[24];
56} ParallelsHeader;
57#pragma pack()
58
59/**
60 * Parallels image structure.
61 */
62typedef struct PARALLELSIMAGE
63{
[32536]64 /** Image file name. */
65 const char *pszFilename;
66 /** Opaque storage handle. */
67 PVDIOSTORAGE pStorage;
68
[21371]69 /** Pointer to the per-disk VD interface list. */
[28620]70 PVDINTERFACE pVDIfsDisk;
71 /** Pointer to the per-image VD interface list. */
72 PVDINTERFACE pVDIfsImage;
[21371]73 /** Error interface. */
[38469]74 PVDINTERFACEERROR pIfError;
75 /** I/O interface. */
76 PVDINTERFACEIOINT pIfIo;
[21371]77
[32536]78 /** Open flags passed by VBoxHDD layer. */
[21371]79 unsigned uOpenFlags;
80 /** Image flags defined during creation or determined during open. */
81 unsigned uImageFlags;
82 /** Total size of the image. */
83 uint64_t cbSize;
[32536]84
[21371]85 /** Physical geometry of this image. */
[32536]86 VDGEOMETRY PCHSGeometry;
[21371]87 /** Logical geometry of this image. */
[32536]88 VDGEOMETRY LCHSGeometry;
89
[21371]90 /** Pointer to the allocation bitmap. */
91 uint32_t *pAllocationBitmap;
92 /** Entries in the allocation bitmap. */
93 uint64_t cAllocationBitmapEntries;
94 /** Flag whether the allocation bitmap was changed. */
95 bool fAllocationBitmapChanged;
96 /** Current file size. */
97 uint64_t cbFileCurrent;
[66486]98 /** The static region list. */
99 VDREGIONLIST RegionList;
[21371]100} PARALLELSIMAGE, *PPARALLELSIMAGE;
101
102
[57358]103/*********************************************************************************************************************************
104* Static Variables *
105*********************************************************************************************************************************/
106
[21371]107/** NULL-terminated array of supported file extensions. */
[33524]108static const VDFILEEXTENSION s_aParallelsFileExtensions[] =
[21371]109{
[33524]110 {"hdd", VDTYPE_HDD},
111 {NULL, VDTYPE_INVALID}
[21371]112};
113
114/***************************************************
[57372]115 * Internal functions *
[21371]116 **************************************************/
117
118/**
[32536]119 * Internal. Flush image data to disk.
120 */
121static int parallelsFlushImage(PPARALLELSIMAGE pImage)
[22966]122{
123 int rc = VINF_SUCCESS;
124
[32536]125 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
126 return VINF_SUCCESS;
[22966]127
[32536]128 if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
129 && (pImage->fAllocationBitmapChanged))
130 {
131 pImage->fAllocationBitmapChanged = false;
132 /* Write the allocation bitmap to the file. */
[38469]133 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
134 sizeof(ParallelsHeader), pImage->pAllocationBitmap,
[44233]135 pImage->cAllocationBitmapEntries * sizeof(uint32_t));
[32536]136 if (RT_FAILURE(rc))
137 return rc;
138 }
139
140 /* Flush file. */
[38469]141 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
[32536]142
143 LogFlowFunc(("returns %Rrc\n", rc));
[22966]144 return rc;
145}
146
[32536]147/**
148 * Internal. Free all allocated space for representing an image except pImage,
149 * and optionally delete the image from disk.
150 */
151static int parallelsFreeImage(PPARALLELSIMAGE pImage, bool fDelete)
[22966]152{
153 int rc = VINF_SUCCESS;
154
[32536]155 /* Freeing a never allocated image (e.g. because the open failed) is
156 * not signalled as an error. After all nothing bad happens. */
157 if (pImage)
158 {
159 if (pImage->pStorage)
160 {
161 /* No point updating the file that is deleted anyway. */
162 if (!fDelete)
163 parallelsFlushImage(pImage);
[22966]164
[46613]165 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
[32536]166 pImage->pStorage = NULL;
167 }
168
169 if (pImage->pAllocationBitmap)
170 {
171 RTMemFree(pImage->pAllocationBitmap);
172 pImage->pAllocationBitmap = NULL;
173 }
174
175 if (fDelete && pImage->pszFilename)
[38469]176 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
[32536]177 }
178
[22966]179 return rc;
180}
181
[21371]182static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
183{
[38469]184 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
185 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
[46170]186 pImage->uOpenFlags = uOpenFlags;
[38469]187 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
[21371]188
[63780]189 int rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
190 VDOpenFlagsToFileOpenFlags(uOpenFlags,
191 false /* fCreate */),
192 &pImage->pStorage);
193 if (RT_SUCCESS(rc))
[63635]194 {
[63780]195 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbFileCurrent);
196 if (RT_SUCCESS(rc)
197 && !(pImage->cbFileCurrent % 512))
[21371]198 {
[63780]199 ParallelsHeader parallelsHeader;
[21371]200
[63780]201 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0,
202 &parallelsHeader, sizeof(parallelsHeader));
203 if (RT_SUCCESS(rc))
204 {
205 if (memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16))
206 {
207 /* Check if the file has hdd as extension. It is a fixed size raw image then. */
208 char *pszSuffix = RTPathSuffix(pImage->pszFilename);
209 if (!strcmp(pszSuffix, ".hdd"))
210 {
211 /* This is a fixed size image. */
212 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
213 pImage->cbSize = pImage->cbFileCurrent;
[21371]214
[63780]215 pImage->PCHSGeometry.cHeads = 16;
216 pImage->PCHSGeometry.cSectors = 63;
217 uint64_t cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
218 pImage->PCHSGeometry.cCylinders = (uint32_t)cCylinders;
219 }
220 else
221 rc = VERR_VD_PARALLELS_INVALID_HEADER;
222 }
223 else
224 {
225 if ( parallelsHeader.uVersion == PARALLELS_DISK_VERSION
226 && parallelsHeader.cEntriesInAllocationBitmap <= (1 << 30))
227 {
228 Log(("cSectors=%u\n", parallelsHeader.cSectors));
229 pImage->cbSize = ((uint64_t)parallelsHeader.cSectors) * 512;
230 pImage->uImageFlags = VD_IMAGE_FLAGS_NONE;
231 pImage->PCHSGeometry.cCylinders = parallelsHeader.cCylinders;
232 pImage->PCHSGeometry.cHeads = parallelsHeader.cHeads;
233 pImage->PCHSGeometry.cSectors = parallelsHeader.cSectorsPerTrack;
234 pImage->cAllocationBitmapEntries = parallelsHeader.cEntriesInAllocationBitmap;
235 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ((uint32_t)pImage->cAllocationBitmapEntries * sizeof(uint32_t));
236 if (RT_LIKELY(pImage->pAllocationBitmap))
237 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
238 sizeof(ParallelsHeader), pImage->pAllocationBitmap,
239 pImage->cAllocationBitmapEntries * sizeof(uint32_t));
240 else
241 rc = VERR_NO_MEMORY;
242 }
243 else
244 rc = VERR_NOT_SUPPORTED;
245 }
246 }
[21371]247 }
[63780]248 else if (RT_SUCCESS(rc))
249 rc = VERR_VD_PARALLELS_INVALID_HEADER;
[21371]250 }
251
[66486]252 if (RT_SUCCESS(rc))
253 {
254 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
255 pImage->RegionList.fFlags = 0;
256 pImage->RegionList.cRegions = 1;
257
258 pRegion->offRegion = 0; /* Disk start. */
259 pRegion->cbBlock = 512;
260 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
261 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
262 pRegion->cbData = 512;
263 pRegion->cbMetadata = 0;
264 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
265 }
[77699]266 else
267 parallelsFreeImage(pImage, false);
[66486]268
[21371]269 LogFlowFunc(("returns %Rrc\n", rc));
270 return rc;
271}
272
[38413]273/**
274 * Internal: Create a parallels image.
275 */
276static int parallelsCreateImage(PPARALLELSIMAGE pImage, uint64_t cbSize,
277 unsigned uImageFlags, const char *pszComment,
278 PCVDGEOMETRY pPCHSGeometry,
279 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
280 PFNVDPROGRESS pfnProgress, void *pvUser,
281 unsigned uPercentStart, unsigned uPercentSpan)
282{
[62751]283 RT_NOREF1(pszComment);
[38413]284 int rc = VINF_SUCCESS;
285 int32_t fOpen;
[21371]286
[63780]287 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
[38413]288 {
[63780]289 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
290 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
291 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
[38413]292
[63780]293 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
294 pImage->uImageFlags = uImageFlags;
295 pImage->PCHSGeometry = *pPCHSGeometry;
296 pImage->LCHSGeometry = *pLCHSGeometry;
297 if (!pImage->PCHSGeometry.cCylinders)
298 {
299 /* Set defaults. */
300 pImage->PCHSGeometry.cSectors = 63;
301 pImage->PCHSGeometry.cHeads = 16;
302 pImage->PCHSGeometry.cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
303 }
[38413]304
[63780]305 /* Create image file. */
306 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
307 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
308 if (RT_SUCCESS(rc))
309 {
310 if (pfnProgress)
311 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
[38413]312
[63780]313 /* Setup image state. */
314 pImage->cbSize = cbSize;
315 pImage->cAllocationBitmapEntries = cbSize / 512 / pImage->PCHSGeometry.cSectors;
316 if (pImage->cAllocationBitmapEntries * pImage->PCHSGeometry.cSectors * 512 < cbSize)
317 pImage->cAllocationBitmapEntries++;
318 pImage->fAllocationBitmapChanged = true;
319 pImage->cbFileCurrent = sizeof(ParallelsHeader) + pImage->cAllocationBitmapEntries * sizeof(uint32_t);
320 /* Round to next sector boundary. */
321 pImage->cbFileCurrent += 512 - pImage->cbFileCurrent % 512;
322 Assert(!(pImage->cbFileCurrent % 512));
323 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ(pImage->cAllocationBitmapEntries * sizeof(uint32_t));
324 if (pImage->pAllocationBitmap)
325 {
326 ParallelsHeader Header;
[38413]327
[63780]328 memcpy(Header.HeaderIdentifier, PARALLELS_HEADER_MAGIC, sizeof(Header.HeaderIdentifier));
329 Header.uVersion = RT_H2LE_U32(PARALLELS_DISK_VERSION);
330 Header.cHeads = RT_H2LE_U32(pImage->PCHSGeometry.cHeads);
331 Header.cCylinders = RT_H2LE_U32(pImage->PCHSGeometry.cCylinders);
332 Header.cSectorsPerTrack = RT_H2LE_U32(pImage->PCHSGeometry.cSectors);
333 Header.cEntriesInAllocationBitmap = RT_H2LE_U32(pImage->cAllocationBitmapEntries);
334 Header.cSectors = RT_H2LE_U32(pImage->cbSize / 512);
335 memset(Header.Padding, 0, sizeof(Header.Padding));
[38413]336
[63780]337 /* Write header and allocation bitmap. */
338 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbFileCurrent);
339 if (RT_SUCCESS(rc))
340 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0,
341 &Header, sizeof(Header));
342 if (RT_SUCCESS(rc))
343 rc = parallelsFlushImage(pImage); /* Writes the allocation bitmap. */
344 }
345 else
346 rc = VERR_NO_MEMORY;
347 }
348 else
349 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Parallels: cannot create image '%s'"), pImage->pszFilename);
[38413]350 }
[63780]351 else
352 rc = vdIfError(pImage->pIfError, VERR_VD_INVALID_TYPE, RT_SRC_POS, N_("Parallels: cannot create fixed image '%s'. Create a raw image"), pImage->pszFilename);
[38413]353
354 if (RT_SUCCESS(rc) && pfnProgress)
355 pfnProgress(pvUser, uPercentStart + uPercentSpan);
356
[66486]357 if (RT_SUCCESS(rc))
358 {
359 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
360 pImage->RegionList.fFlags = 0;
361 pImage->RegionList.cRegions = 1;
362
363 pRegion->offRegion = 0; /* Disk start. */
364 pRegion->cbBlock = 512;
365 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
366 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
367 pRegion->cbData = 512;
368 pRegion->cbMetadata = 0;
369 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
370 }
371 else
[38413]372 parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
373 return rc;
374}
375
[64277]376/** @copydoc VDIMAGEBACKEND::pfnProbe */
[63802]377static DECLCALLBACK(int) parallelsProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
378 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
[21371]379{
[62751]380 RT_NOREF1(pVDIfsDisk);
[32536]381 int rc;
382 PVDIOSTORAGE pStorage;
[21371]383 ParallelsHeader parallelsHeader;
384
[38469]385 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
386 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
[32536]387
[38469]388 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
389 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
390 false /* fCreate */),
391 &pStorage);
[21371]392 if (RT_FAILURE(rc))
[32536]393 return rc;
[21371]394
[38469]395 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &parallelsHeader,
[44233]396 sizeof(ParallelsHeader));
[32536]397 if (RT_SUCCESS(rc))
[21371]398 {
399 if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
400 && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
401 rc = VINF_SUCCESS;
402 else
403 {
404 /*
405 * The image may be an fixed size image.
406 * Unfortunately fixed sized parallels images
407 * are just raw files hence no magic header to
408 * check for.
409 * The code succeeds if the file is a multiple
410 * of 512 and if the file extensions is *.hdd
411 */
412 uint64_t cbFile;
[49039]413 char *pszSuffix;
[21371]414
[38469]415 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
[21371]416 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
417 {
[38469]418 vdIfIoIntFileClose(pIfIo, pStorage);
[32536]419 return VERR_VD_PARALLELS_INVALID_HEADER;
[21371]420 }
421
[49039]422 pszSuffix = RTPathSuffix(pszFilename);
423 if (!pszSuffix || strcmp(pszSuffix, ".hdd"))
[32536]424 rc = VERR_VD_PARALLELS_INVALID_HEADER;
[21371]425 else
426 rc = VINF_SUCCESS;
427 }
428 }
429
[33524]430 if (RT_SUCCESS(rc))
431 *penmType = VDTYPE_HDD;
432
[38469]433 vdIfIoIntFileClose(pIfIo, pStorage);
[21371]434 return rc;
435}
436
[63783]437/** @copydoc VDIMAGEBACKEND::pfnOpen */
[57388]438static DECLCALLBACK(int) parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
439 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
440 VDTYPE enmType, void **ppBackendData)
[21371]441{
[54430]442 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
[21371]443 int rc;
444 PPARALLELSIMAGE pImage;
445
[54430]446 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
447
[63780]448 /* Check parameters. */
449 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
450 AssertReturn(VALID_PTR(pszFilename) && *pszFilename, VERR_INVALID_PARAMETER);
[21371]451
[66486]452 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
[63780]453 if (RT_LIKELY(pImage))
[21371]454 {
[63780]455 pImage->pszFilename = pszFilename;
456 pImage->pStorage = NULL;
457 pImage->pVDIfsDisk = pVDIfsDisk;
458 pImage->pVDIfsImage = pVDIfsImage;
459 pImage->fAllocationBitmapChanged = false;
[21371]460
[63780]461 rc = parallelsOpenImage(pImage, uOpenFlags);
462 if (RT_SUCCESS(rc))
463 *ppBackendData = pImage;
464 else
465 RTMemFree(pImage);
[21371]466 }
[32536]467 else
[63780]468 rc = VERR_NO_MEMORY;
[21371]469
470 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
471 return rc;
472}
473
[63783]474/** @copydoc VDIMAGEBACKEND::pfnCreate */
[57388]475static DECLCALLBACK(int) parallelsCreate(const char *pszFilename, uint64_t cbSize,
476 unsigned uImageFlags, const char *pszComment,
477 PCVDGEOMETRY pPCHSGeometry,
478 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
479 unsigned uOpenFlags, unsigned uPercentStart,
480 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
481 PVDINTERFACE pVDIfsImage,
482 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
483 void **ppBackendData)
[21371]484{
[62751]485 RT_NOREF1(pUuid);
[54430]486 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p enmType=%u ppBackendData=%#p",
487 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
[63780]488
489 /* Check the VD container type. */
490 if (enmType != VDTYPE_HDD)
491 return VERR_VD_INVALID_TYPE;
492
493 /* Check arguments. */
494 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
495 AssertReturn( VALID_PTR(pszFilename)
496 && *pszFilename
497 && VALID_PTR(pPCHSGeometry)
498 && VALID_PTR(pLCHSGeometry), VERR_INVALID_PARAMETER);
499
[38413]500 int rc = VINF_SUCCESS;
501 PPARALLELSIMAGE pImage;
502 PFNVDPROGRESS pfnProgress = NULL;
503 void *pvUser = NULL;
[38469]504 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
[38413]505 if (pIfProgress)
506 {
[38469]507 pfnProgress = pIfProgress->pfnProgress;
508 pvUser = pIfProgress->Core.pvUser;
[38413]509 }
510
[66486]511 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
[63780]512 if (RT_LIKELY(pImage))
[38413]513 {
[63780]514 pImage->pszFilename = pszFilename;
515 pImage->pStorage = NULL;
516 pImage->pVDIfsDisk = pVDIfsDisk;
517 pImage->pVDIfsImage = pVDIfsImage;
[38413]518
[63780]519 rc = parallelsCreateImage(pImage, cbSize, uImageFlags, pszComment,
520 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
521 pfnProgress, pvUser, uPercentStart, uPercentSpan);
522 if (RT_SUCCESS(rc))
[38413]523 {
[63780]524 /* So far the image is opened in read/write mode. Make sure the
525 * image is opened in read-only mode if the caller requested that. */
526 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
[38413]527 {
[63780]528 parallelsFreeImage(pImage, false);
529 rc = parallelsOpenImage(pImage, uOpenFlags);
[38413]530 }
[63780]531
532 if (RT_SUCCESS(rc))
533 *ppBackendData = pImage;
[38413]534 }
[63780]535
536 if (RT_FAILURE(rc))
537 RTMemFree(pImage);
[38413]538 }
539 else
[63780]540 rc = VERR_NO_MEMORY;
[38413]541
[32536]542 LogFlowFunc(("returns %Rrc\n", rc));
543 return rc;
[21371]544}
545
[63783]546/** @copydoc VDIMAGEBACKEND::pfnRename */
[57388]547static DECLCALLBACK(int) parallelsRename(void *pBackendData, const char *pszFilename)
[21371]548{
549 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
[32536]550 int rc = VINF_SUCCESS;
551 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
552
553 /* Check arguments. */
[63780]554 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
[32536]555
556 /* Close the image. */
557 rc = parallelsFreeImage(pImage, false);
[63780]558 if (RT_SUCCESS(rc))
[32536]559 {
[63780]560 /* Rename the file. */
561 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
562 if (RT_SUCCESS(rc))
563 {
564 /* Update pImage with the new information. */
565 pImage->pszFilename = pszFilename;
[32536]566
[63780]567 /* Open the old image with new name. */
568 rc = parallelsOpenImage(pImage, pImage->uOpenFlags);
569 }
570 else
571 {
572 /* The move failed, try to reopen the original image. */
573 int rc2 = parallelsOpenImage(pImage, pImage->uOpenFlags);
574 if (RT_FAILURE(rc2))
575 rc = rc2;
576 }
[32536]577 }
578
579 LogFlowFunc(("returns %Rrc\n", rc));
580 return rc;
[21371]581}
582
[63783]583/** @copydoc VDIMAGEBACKEND::pfnClose */
[57388]584static DECLCALLBACK(int) parallelsClose(void *pBackendData, bool fDelete)
[21371]585{
586 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
587 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]588 int rc = parallelsFreeImage(pImage, fDelete);
[32536]589 RTMemFree(pImage);
[21371]590
591 LogFlowFunc(("returns %Rrc\n", rc));
592 return rc;
593}
594
[63783]595/** @copydoc VDIMAGEBACKEND::pfnRead */
[57388]596static DECLCALLBACK(int) parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
597 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
[21371]598{
[44252]599 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
600 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
601 int rc = VINF_SUCCESS;
[32536]602 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[44252]603 uint64_t uSector;
604 uint64_t uOffsetInFile;
605 uint32_t iIndexInAllocationTable;
[21371]606
[32536]607 AssertPtr(pImage);
[21371]608 Assert(uOffset % 512 == 0);
[38413]609 Assert(cbToRead % 512 == 0);
[21371]610
611 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
[44252]612 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
613 pIoCtx, cbToRead);
[21371]614 else
615 {
[30863]616 /* Calculate offset in the real file. */
[21371]617 uSector = uOffset / 512;
[30863]618 /* One chunk in the file is always one track big. */
[21371]619 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
620 uSector = uSector % pImage->PCHSGeometry.cSectors;
621
[38413]622 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
623
[21371]624 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
625 rc = VERR_VD_BLOCK_FREE;
626 else
627 {
[44252]628 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
629 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
630 pIoCtx, cbToRead);
[21371]631 }
632 }
633
[44252]634 *pcbActuallyRead = cbToRead;
[21371]635
636 LogFlowFunc(("returns %Rrc\n", rc));
637 return rc;
638}
639
[63783]640/** @copydoc VDIMAGEBACKEND::pfnWrite */
[57388]641static DECLCALLBACK(int) parallelsWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
642 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
643 size_t *pcbPostRead, unsigned fWrite)
[21371]644{
[44252]645 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
646 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
647 int rc = VINF_SUCCESS;
[32536]648 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[44252]649 uint64_t uSector;
650 uint64_t uOffsetInFile;
651 uint32_t iIndexInAllocationTable;
[21371]652
[32536]653 AssertPtr(pImage);
[21371]654 Assert(uOffset % 512 == 0);
[38413]655 Assert(cbToWrite % 512 == 0);
[21371]656
657 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
[44252]658 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
659 pIoCtx, cbToWrite, NULL, NULL);
[21371]660 else
661 {
[38413]662 /* Calculate offset in the real file. */
[21371]663 uSector = uOffset / 512;
[38413]664 /* One chunk in the file is always one track big. */
[21371]665 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
666 uSector = uSector % pImage->PCHSGeometry.cSectors;
667
[38413]668 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
669
[21371]670 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
671 {
[44252]672 if (fWrite & VD_WRITE_NO_ALLOC)
[38413]673 {
[44252]674 *pcbPreRead = uSector * 512;
675 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
[22966]676
[44252]677 if (pcbWriteProcess)
678 *pcbWriteProcess = cbToWrite;
679 return VERR_VD_BLOCK_FREE;
680 }
[22966]681
[44252]682 /* Allocate new chunk in the file. */
683 Assert(uSector == 0);
684 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
685 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
686 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
687 pImage->fAllocationBitmapChanged = true;
688 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
[38413]689
[44252]690 /*
691 * Write the new block at the current end of the file.
692 */
693 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
694 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
695 if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
[32536]696 {
[44252]697 /* Write the changed allocation bitmap entry. */
[63567]698 /** @todo Error handling. */
[44252]699 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
700 sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
701 &pImage->pAllocationBitmap[iIndexInAllocationTable],
702 sizeof(uint32_t), pIoCtx,
703 NULL, NULL);
[32536]704 }
[44252]705
706 *pcbPreRead = 0;
707 *pcbPostRead = 0;
[21371]708 }
[22966]709 else
710 {
[44252]711 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
712 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
713 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
[22966]714 }
[21371]715 }
716
[32536]717 if (pcbWriteProcess)
[38413]718 *pcbWriteProcess = cbToWrite;
[21371]719
720 LogFlowFunc(("returns %Rrc\n", rc));
721 return rc;
722}
723
[63783]724/** @copydoc VDIMAGEBACKEND::pfnFlush */
[57388]725static DECLCALLBACK(int) parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
[21371]726{
[44252]727 int rc = VINF_SUCCESS;
[21371]728 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
729
[44252]730 LogFlowFunc(("pImage=#%p\n", pImage));
[21371]731
[44252]732 /* Flush the file, everything is up to date already. */
733 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
[21371]734
735 LogFlowFunc(("returns %Rrc\n", rc));
736 return rc;
737}
738
[63783]739/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
[57388]740static DECLCALLBACK(unsigned) parallelsGetVersion(void *pBackendData)
[21371]741{
742 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
743 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
744
[63780]745 AssertPtrReturn(pImage, 0);
[21371]746
[63780]747 return PARALLELS_DISK_VERSION;
[21371]748}
749
[63783]750/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
[57388]751static DECLCALLBACK(uint64_t) parallelsGetFileSize(void *pBackendData)
[21371]752{
753 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
754 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
755 uint64_t cb = 0;
756
[63780]757 AssertPtrReturn(pImage, 0);
[21371]758
[63780]759 if (pImage->pStorage)
[32536]760 cb = pImage->cbFileCurrent;
[21371]761
762 LogFlowFunc(("returns %lld\n", cb));
763 return cb;
764}
765
[63783]766/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
[57388]767static DECLCALLBACK(int) parallelsGetPCHSGeometry(void *pBackendData,
768 PVDGEOMETRY pPCHSGeometry)
[21371]769{
770 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
771 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]772 int rc = VINF_SUCCESS;
[21371]773
[63780]774 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]775
[63780]776 if (pImage->PCHSGeometry.cCylinders)
777 *pPCHSGeometry = pImage->PCHSGeometry;
[21371]778 else
[63780]779 rc = VERR_VD_GEOMETRY_NOT_SET;
[21371]780
781 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
782 return rc;
783}
784
[63783]785/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
[57388]786static DECLCALLBACK(int) parallelsSetPCHSGeometry(void *pBackendData,
787 PCVDGEOMETRY pPCHSGeometry)
[21371]788{
[63780]789 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData,
790 pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
[21371]791 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]792 int rc = VINF_SUCCESS;
[21371]793
[63780]794 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]795
[63780]796 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
797 rc = VERR_VD_IMAGE_READ_ONLY;
798 else
[21371]799 pImage->PCHSGeometry = *pPCHSGeometry;
800
801 LogFlowFunc(("returns %Rrc\n", rc));
802 return rc;
803}
804
[63783]805/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
[57388]806static DECLCALLBACK(int) parallelsGetLCHSGeometry(void *pBackendData,
807 PVDGEOMETRY pLCHSGeometry)
[21371]808{
809 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
810 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]811 int rc = VINF_SUCCESS;
[21371]812
[63780]813 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]814
[63780]815 if (pImage->LCHSGeometry.cCylinders)
816 *pLCHSGeometry = pImage->LCHSGeometry;
[21371]817 else
[63780]818 rc = VERR_VD_GEOMETRY_NOT_SET;
[21371]819
820 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
821 return rc;
822}
823
[63783]824/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
[57388]825static DECLCALLBACK(int) parallelsSetLCHSGeometry(void *pBackendData,
826 PCVDGEOMETRY pLCHSGeometry)
[21371]827{
828 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
829 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]830 int rc = VINF_SUCCESS;
[21371]831
[63780]832 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]833
[63780]834 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
835 rc = VERR_VD_IMAGE_READ_ONLY;
836 else
[21371]837 pImage->LCHSGeometry = *pLCHSGeometry;
838
839 LogFlowFunc(("returns %Rrc\n", rc));
840 return rc;
841}
842
[66486]843/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
844static DECLCALLBACK(int) parallelsQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
845{
846 LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
847 PPARALLELSIMAGE pThis = (PPARALLELSIMAGE)pBackendData;
848
849 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
850
851 *ppRegionList = &pThis->RegionList;
852 LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
853 return VINF_SUCCESS;
854}
855
856/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
857static DECLCALLBACK(void) parallelsRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
858{
859 RT_NOREF1(pRegionList);
860 LogFlowFunc(("pBackendData=%#p pRegionList=%#p\n", pBackendData, pRegionList));
861 PPARALLELSIMAGE pThis = (PPARALLELSIMAGE)pBackendData;
862 AssertPtr(pThis); RT_NOREF(pThis);
863
864 /* Nothing to do here. */
865}
866
[63783]867/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
[57388]868static DECLCALLBACK(unsigned) parallelsGetImageFlags(void *pBackendData)
[21371]869{
870 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
871 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
872
[63780]873 AssertPtrReturn(pImage, 0);
[21371]874
[63780]875 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
876 return pImage->uImageFlags;
[21371]877}
878
[63783]879/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
[57388]880static DECLCALLBACK(unsigned) parallelsGetOpenFlags(void *pBackendData)
[21371]881{
882 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
883 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
884
[63780]885 AssertPtrReturn(pImage, 0);
[21371]886
[63780]887 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
888 return pImage->uOpenFlags;
[21371]889}
890
[63783]891/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
[57388]892static DECLCALLBACK(int) parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
[21371]893{
894 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
895 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]896 int rc = VINF_SUCCESS;
[21371]897
[33182]898 /* Image must be opened and the new flags must be valid. */
[44232]899 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
900 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
901 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
[63780]902 rc = VERR_INVALID_PARAMETER;
903 else
[21371]904 {
[63780]905 /* Implement this operation via reopening the image. */
906 parallelsFreeImage(pImage, false);
907 rc = parallelsOpenImage(pImage, uOpenFlags);
[21371]908 }
909
910 LogFlowFunc(("returns %Rrc\n", rc));
911 return rc;
912}
913
[63783]914/** @copydoc VDIMAGEBACKEND::pfnGetComment */
[57388]915static DECLCALLBACK(int) parallelsGetComment(void *pBackendData, char *pszComment,
916 size_t cbComment)
[21371]917{
[62751]918 RT_NOREF2(pszComment, cbComment);
[21371]919 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
920 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
921
[63780]922 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]923
[63780]924 LogFlowFunc(("returns %Rrc comment='%s'\n", VERR_NOT_SUPPORTED, pszComment));
925 return VERR_NOT_SUPPORTED;
[21371]926}
927
[63783]928/** @copydoc VDIMAGEBACKEND::pfnSetComment */
[57388]929static DECLCALLBACK(int) parallelsSetComment(void *pBackendData, const char *pszComment)
[21371]930{
[62751]931 RT_NOREF1(pszComment);
[21371]932 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
933 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
934
[63780]935 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]936
[63780]937 int rc;
938 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
939 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]940 else
[63780]941 rc = VERR_NOT_SUPPORTED;
[21371]942
943 LogFlowFunc(("returns %Rrc\n", rc));
944 return rc;
945}
946
[63783]947/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
[57388]948static DECLCALLBACK(int) parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
[21371]949{
[62751]950 RT_NOREF1(pUuid);
[21371]951 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
952 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
953
[63780]954 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]955
[63780]956 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
957 return VERR_NOT_SUPPORTED;
[21371]958}
959
[63783]960/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
[57388]961static DECLCALLBACK(int) parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
[21371]962{
[62751]963 RT_NOREF1(pUuid);
[21371]964 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
965 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
966
[63780]967 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]968
[63780]969 int rc;
970 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
971 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]972 else
[63780]973 rc = VERR_NOT_SUPPORTED;
[21371]974
975 LogFlowFunc(("returns %Rrc\n", rc));
976 return rc;
977}
978
[63783]979/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
[57388]980static DECLCALLBACK(int) parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
[21371]981{
[62751]982 RT_NOREF1(pUuid);
[21371]983 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
984 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
985
[63780]986 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]987
[63780]988 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
989 return VERR_NOT_SUPPORTED;
[21371]990}
991
[63783]992/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
[57388]993static DECLCALLBACK(int) parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
[21371]994{
[62751]995 RT_NOREF1(pUuid);
[21371]996 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
997 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
998
[63780]999 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1000
[63780]1001 int rc;
1002 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1003 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]1004 else
[63780]1005 rc = VERR_NOT_SUPPORTED;
[21371]1006
1007 LogFlowFunc(("returns %Rrc\n", rc));
1008 return rc;
1009}
1010
[63783]1011/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
[57388]1012static DECLCALLBACK(int) parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
[21371]1013{
[62751]1014 RT_NOREF1(pUuid);
[21371]1015 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1016 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1017
[63780]1018 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1019
[63780]1020 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
1021 return VERR_NOT_SUPPORTED;
[21371]1022}
1023
[63783]1024/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
[57388]1025static DECLCALLBACK(int) parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
[21371]1026{
[62751]1027 RT_NOREF1(pUuid);
[21371]1028 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1029 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1030
[63780]1031 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1032
[63780]1033 int rc;
1034 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1035 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]1036 else
[63780]1037 rc = VERR_NOT_SUPPORTED;
[21371]1038
1039 LogFlowFunc(("returns %Rrc\n", rc));
1040 return rc;
1041}
1042
[63783]1043/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
[57388]1044static DECLCALLBACK(int) parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
[21371]1045{
[62751]1046 RT_NOREF1(pUuid);
[21371]1047 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1048 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1049
[63780]1050 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1051
[63780]1052 int rc;
1053 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1054 rc = VERR_VD_IMAGE_READ_ONLY;
1055 else
[21371]1056 rc = VERR_NOT_SUPPORTED;
1057
1058 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1059 return rc;
1060}
1061
[63783]1062/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
[57388]1063static DECLCALLBACK(int) parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
[21371]1064{
[62751]1065 RT_NOREF1(pUuid);
[21371]1066 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1067 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1068
[63780]1069 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1070
[63780]1071 int rc;
1072 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1073 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]1074 else
[63780]1075 rc = VERR_NOT_SUPPORTED;
[21371]1076
1077 LogFlowFunc(("returns %Rrc\n", rc));
1078 return rc;
1079}
1080
[63783]1081/** @copydoc VDIMAGEBACKEND::pfnDump */
[57388]1082static DECLCALLBACK(void) parallelsDump(void *pBackendData)
[21371]1083{
1084 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1085
[63780]1086 AssertPtrReturnVoid(pImage);
1087 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
1088 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1089 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
[21371]1090}
1091
[30864]1092
1093
[63781]1094const VDIMAGEBACKEND g_ParallelsBackend =
[21371]1095{
[63905]1096 /* u32Version */
1097 VD_IMGBACKEND_VERSION,
[21371]1098 /* pszBackendName */
1099 "Parallels",
1100 /* uBackendCaps */
[38413]1101 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
[33524]1102 /* paFileExtensions */
1103 s_aParallelsFileExtensions,
[21371]1104 /* paConfigInfo */
1105 NULL,
[63802]1106 /* pfnProbe */
1107 parallelsProbe,
[21371]1108 /* pfnOpen */
1109 parallelsOpen,
1110 /* pfnCreate */
1111 parallelsCreate,
1112 /* pfnRename */
1113 parallelsRename,
1114 /* pfnClose */
1115 parallelsClose,
1116 /* pfnRead */
1117 parallelsRead,
1118 /* pfnWrite */
1119 parallelsWrite,
1120 /* pfnFlush */
1121 parallelsFlush,
[44252]1122 /* pfnDiscard */
1123 NULL,
[21371]1124 /* pfnGetVersion */
1125 parallelsGetVersion,
1126 /* pfnGetFileSize */
1127 parallelsGetFileSize,
1128 /* pfnGetPCHSGeometry */
1129 parallelsGetPCHSGeometry,
1130 /* pfnSetPCHSGeometry */
1131 parallelsSetPCHSGeometry,
1132 /* pfnGetLCHSGeometry */
1133 parallelsGetLCHSGeometry,
1134 /* pfnSetLCHSGeometry */
1135 parallelsSetLCHSGeometry,
[66110]1136 /* pfnQueryRegions */
[66486]1137 parallelsQueryRegions,
[66110]1138 /* pfnRegionListRelease */
[66486]1139 parallelsRegionListRelease,
[21371]1140 /* pfnGetImageFlags */
1141 parallelsGetImageFlags,
1142 /* pfnGetOpenFlags */
1143 parallelsGetOpenFlags,
1144 /* pfnSetOpenFlags */
1145 parallelsSetOpenFlags,
1146 /* pfnGetComment */
1147 parallelsGetComment,
1148 /* pfnSetComment */
1149 parallelsSetComment,
1150 /* pfnGetUuid */
1151 parallelsGetUuid,
1152 /* pfnSetUuid */
1153 parallelsSetUuid,
1154 /* pfnGetModificationUuid */
1155 parallelsGetModificationUuid,
1156 /* pfnSetModificationUuid */
1157 parallelsSetModificationUuid,
1158 /* pfnGetParentUuid */
1159 parallelsGetParentUuid,
1160 /* pfnSetParentUuid */
1161 parallelsSetParentUuid,
1162 /* pfnGetParentModificationUuid */
1163 parallelsGetParentModificationUuid,
1164 /* pfnSetParentModificationUuid */
1165 parallelsSetParentModificationUuid,
1166 /* pfnDump */
1167 parallelsDump,
[58132]1168 /* pfnGetTimestamp */
[32536]1169 NULL,
[58132]1170 /* pfnGetParentTimestamp */
[32536]1171 NULL,
[58132]1172 /* pfnSetParentTimestamp */
[32536]1173 NULL,
[21371]1174 /* pfnGetParentFilename */
[32536]1175 NULL,
[21371]1176 /* pfnSetParentFilename */
[32536]1177 NULL,
[21371]1178 /* pfnComposeLocation */
1179 genericFileComposeLocation,
1180 /* pfnComposeName */
[26291]1181 genericFileComposeName,
1182 /* pfnCompact */
[31776]1183 NULL,
1184 /* pfnResize */
[44101]1185 NULL,
1186 /* pfnRepair */
[50988]1187 NULL,
1188 /* pfnTraverseMetadata */
[63905]1189 NULL,
1190 /* u32VersionEnd */
1191 VD_IMGBACKEND_VERSION
[21371]1192};
Note: See TracBrowser for help on using the repository browser.

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