VirtualBox

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

Last change on this file since 67954 was 66486, checked in by vboxsync, 8 years ago

Storage/VD: Convert all backends to use the region list callbacks, remove the pfnGetSize and pfnGetSectorSize callbacks because they are covered by the region lists

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.3 KB
RevLine 
[21371]1/* $Id: Parallels.cpp 66486 2017-04-10 07:23:59Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
[62482]8 * Copyright (C) 2006-2016 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 }
266
[21371]267 LogFlowFunc(("returns %Rrc\n", rc));
268 return rc;
269}
270
[38413]271/**
272 * Internal: Create a parallels image.
273 */
274static int parallelsCreateImage(PPARALLELSIMAGE pImage, uint64_t cbSize,
275 unsigned uImageFlags, const char *pszComment,
276 PCVDGEOMETRY pPCHSGeometry,
277 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
278 PFNVDPROGRESS pfnProgress, void *pvUser,
279 unsigned uPercentStart, unsigned uPercentSpan)
280{
[62751]281 RT_NOREF1(pszComment);
[38413]282 int rc = VINF_SUCCESS;
283 int32_t fOpen;
[21371]284
[63780]285 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
[38413]286 {
[63780]287 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
288 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
289 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
[38413]290
[63780]291 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
292 pImage->uImageFlags = uImageFlags;
293 pImage->PCHSGeometry = *pPCHSGeometry;
294 pImage->LCHSGeometry = *pLCHSGeometry;
295 if (!pImage->PCHSGeometry.cCylinders)
296 {
297 /* Set defaults. */
298 pImage->PCHSGeometry.cSectors = 63;
299 pImage->PCHSGeometry.cHeads = 16;
300 pImage->PCHSGeometry.cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
301 }
[38413]302
[63780]303 /* Create image file. */
304 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
305 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
306 if (RT_SUCCESS(rc))
307 {
308 if (pfnProgress)
309 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
[38413]310
[63780]311 /* Setup image state. */
312 pImage->cbSize = cbSize;
313 pImage->cAllocationBitmapEntries = cbSize / 512 / pImage->PCHSGeometry.cSectors;
314 if (pImage->cAllocationBitmapEntries * pImage->PCHSGeometry.cSectors * 512 < cbSize)
315 pImage->cAllocationBitmapEntries++;
316 pImage->fAllocationBitmapChanged = true;
317 pImage->cbFileCurrent = sizeof(ParallelsHeader) + pImage->cAllocationBitmapEntries * sizeof(uint32_t);
318 /* Round to next sector boundary. */
319 pImage->cbFileCurrent += 512 - pImage->cbFileCurrent % 512;
320 Assert(!(pImage->cbFileCurrent % 512));
321 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ(pImage->cAllocationBitmapEntries * sizeof(uint32_t));
322 if (pImage->pAllocationBitmap)
323 {
324 ParallelsHeader Header;
[38413]325
[63780]326 memcpy(Header.HeaderIdentifier, PARALLELS_HEADER_MAGIC, sizeof(Header.HeaderIdentifier));
327 Header.uVersion = RT_H2LE_U32(PARALLELS_DISK_VERSION);
328 Header.cHeads = RT_H2LE_U32(pImage->PCHSGeometry.cHeads);
329 Header.cCylinders = RT_H2LE_U32(pImage->PCHSGeometry.cCylinders);
330 Header.cSectorsPerTrack = RT_H2LE_U32(pImage->PCHSGeometry.cSectors);
331 Header.cEntriesInAllocationBitmap = RT_H2LE_U32(pImage->cAllocationBitmapEntries);
332 Header.cSectors = RT_H2LE_U32(pImage->cbSize / 512);
333 memset(Header.Padding, 0, sizeof(Header.Padding));
[38413]334
[63780]335 /* Write header and allocation bitmap. */
336 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbFileCurrent);
337 if (RT_SUCCESS(rc))
338 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0,
339 &Header, sizeof(Header));
340 if (RT_SUCCESS(rc))
341 rc = parallelsFlushImage(pImage); /* Writes the allocation bitmap. */
342 }
343 else
344 rc = VERR_NO_MEMORY;
345 }
346 else
347 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Parallels: cannot create image '%s'"), pImage->pszFilename);
[38413]348 }
[63780]349 else
350 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]351
352 if (RT_SUCCESS(rc) && pfnProgress)
353 pfnProgress(pvUser, uPercentStart + uPercentSpan);
354
[66486]355 if (RT_SUCCESS(rc))
356 {
357 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
358 pImage->RegionList.fFlags = 0;
359 pImage->RegionList.cRegions = 1;
360
361 pRegion->offRegion = 0; /* Disk start. */
362 pRegion->cbBlock = 512;
363 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
364 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
365 pRegion->cbData = 512;
366 pRegion->cbMetadata = 0;
367 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
368 }
369 else
[38413]370 parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
371 return rc;
372}
373
[64277]374/** @copydoc VDIMAGEBACKEND::pfnProbe */
[63802]375static DECLCALLBACK(int) parallelsProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
376 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
[21371]377{
[62751]378 RT_NOREF1(pVDIfsDisk);
[32536]379 int rc;
380 PVDIOSTORAGE pStorage;
[21371]381 ParallelsHeader parallelsHeader;
382
[38469]383 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
384 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
[32536]385
[38469]386 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
387 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
388 false /* fCreate */),
389 &pStorage);
[21371]390 if (RT_FAILURE(rc))
[32536]391 return rc;
[21371]392
[38469]393 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &parallelsHeader,
[44233]394 sizeof(ParallelsHeader));
[32536]395 if (RT_SUCCESS(rc))
[21371]396 {
397 if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
398 && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
399 rc = VINF_SUCCESS;
400 else
401 {
402 /*
403 * The image may be an fixed size image.
404 * Unfortunately fixed sized parallels images
405 * are just raw files hence no magic header to
406 * check for.
407 * The code succeeds if the file is a multiple
408 * of 512 and if the file extensions is *.hdd
409 */
410 uint64_t cbFile;
[49039]411 char *pszSuffix;
[21371]412
[38469]413 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
[21371]414 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
415 {
[38469]416 vdIfIoIntFileClose(pIfIo, pStorage);
[32536]417 return VERR_VD_PARALLELS_INVALID_HEADER;
[21371]418 }
419
[49039]420 pszSuffix = RTPathSuffix(pszFilename);
421 if (!pszSuffix || strcmp(pszSuffix, ".hdd"))
[32536]422 rc = VERR_VD_PARALLELS_INVALID_HEADER;
[21371]423 else
424 rc = VINF_SUCCESS;
425 }
426 }
427
[33524]428 if (RT_SUCCESS(rc))
429 *penmType = VDTYPE_HDD;
430
[38469]431 vdIfIoIntFileClose(pIfIo, pStorage);
[21371]432 return rc;
433}
434
[63783]435/** @copydoc VDIMAGEBACKEND::pfnOpen */
[57388]436static DECLCALLBACK(int) parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
437 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
438 VDTYPE enmType, void **ppBackendData)
[21371]439{
[54430]440 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
[21371]441 int rc;
442 PPARALLELSIMAGE pImage;
443
[54430]444 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
445
[63780]446 /* Check parameters. */
447 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
448 AssertReturn(VALID_PTR(pszFilename) && *pszFilename, VERR_INVALID_PARAMETER);
[21371]449
[66486]450 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
[63780]451 if (RT_LIKELY(pImage))
[21371]452 {
[63780]453 pImage->pszFilename = pszFilename;
454 pImage->pStorage = NULL;
455 pImage->pVDIfsDisk = pVDIfsDisk;
456 pImage->pVDIfsImage = pVDIfsImage;
457 pImage->fAllocationBitmapChanged = false;
[21371]458
[63780]459 rc = parallelsOpenImage(pImage, uOpenFlags);
460 if (RT_SUCCESS(rc))
461 *ppBackendData = pImage;
462 else
463 RTMemFree(pImage);
[21371]464 }
[32536]465 else
[63780]466 rc = VERR_NO_MEMORY;
[21371]467
468 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
469 return rc;
470}
471
[63783]472/** @copydoc VDIMAGEBACKEND::pfnCreate */
[57388]473static DECLCALLBACK(int) parallelsCreate(const char *pszFilename, uint64_t cbSize,
474 unsigned uImageFlags, const char *pszComment,
475 PCVDGEOMETRY pPCHSGeometry,
476 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
477 unsigned uOpenFlags, unsigned uPercentStart,
478 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
479 PVDINTERFACE pVDIfsImage,
480 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
481 void **ppBackendData)
[21371]482{
[62751]483 RT_NOREF1(pUuid);
[54430]484 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",
485 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
[63780]486
487 /* Check the VD container type. */
488 if (enmType != VDTYPE_HDD)
489 return VERR_VD_INVALID_TYPE;
490
491 /* Check arguments. */
492 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
493 AssertReturn( VALID_PTR(pszFilename)
494 && *pszFilename
495 && VALID_PTR(pPCHSGeometry)
496 && VALID_PTR(pLCHSGeometry), VERR_INVALID_PARAMETER);
497
[38413]498 int rc = VINF_SUCCESS;
499 PPARALLELSIMAGE pImage;
500 PFNVDPROGRESS pfnProgress = NULL;
501 void *pvUser = NULL;
[38469]502 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
[38413]503 if (pIfProgress)
504 {
[38469]505 pfnProgress = pIfProgress->pfnProgress;
506 pvUser = pIfProgress->Core.pvUser;
[38413]507 }
508
[66486]509 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
[63780]510 if (RT_LIKELY(pImage))
[38413]511 {
[63780]512 pImage->pszFilename = pszFilename;
513 pImage->pStorage = NULL;
514 pImage->pVDIfsDisk = pVDIfsDisk;
515 pImage->pVDIfsImage = pVDIfsImage;
[38413]516
[63780]517 rc = parallelsCreateImage(pImage, cbSize, uImageFlags, pszComment,
518 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
519 pfnProgress, pvUser, uPercentStart, uPercentSpan);
520 if (RT_SUCCESS(rc))
[38413]521 {
[63780]522 /* So far the image is opened in read/write mode. Make sure the
523 * image is opened in read-only mode if the caller requested that. */
524 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
[38413]525 {
[63780]526 parallelsFreeImage(pImage, false);
527 rc = parallelsOpenImage(pImage, uOpenFlags);
[38413]528 }
[63780]529
530 if (RT_SUCCESS(rc))
531 *ppBackendData = pImage;
[38413]532 }
[63780]533
534 if (RT_FAILURE(rc))
535 RTMemFree(pImage);
[38413]536 }
537 else
[63780]538 rc = VERR_NO_MEMORY;
[38413]539
[32536]540 LogFlowFunc(("returns %Rrc\n", rc));
541 return rc;
[21371]542}
543
[63783]544/** @copydoc VDIMAGEBACKEND::pfnRename */
[57388]545static DECLCALLBACK(int) parallelsRename(void *pBackendData, const char *pszFilename)
[21371]546{
547 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
[32536]548 int rc = VINF_SUCCESS;
549 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
550
551 /* Check arguments. */
[63780]552 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
[32536]553
554 /* Close the image. */
555 rc = parallelsFreeImage(pImage, false);
[63780]556 if (RT_SUCCESS(rc))
[32536]557 {
[63780]558 /* Rename the file. */
559 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
560 if (RT_SUCCESS(rc))
561 {
562 /* Update pImage with the new information. */
563 pImage->pszFilename = pszFilename;
[32536]564
[63780]565 /* Open the old image with new name. */
566 rc = parallelsOpenImage(pImage, pImage->uOpenFlags);
567 }
568 else
569 {
570 /* The move failed, try to reopen the original image. */
571 int rc2 = parallelsOpenImage(pImage, pImage->uOpenFlags);
572 if (RT_FAILURE(rc2))
573 rc = rc2;
574 }
[32536]575 }
576
577 LogFlowFunc(("returns %Rrc\n", rc));
578 return rc;
[21371]579}
580
[63783]581/** @copydoc VDIMAGEBACKEND::pfnClose */
[57388]582static DECLCALLBACK(int) parallelsClose(void *pBackendData, bool fDelete)
[21371]583{
584 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
585 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]586 int rc = parallelsFreeImage(pImage, fDelete);
[32536]587 RTMemFree(pImage);
[21371]588
589 LogFlowFunc(("returns %Rrc\n", rc));
590 return rc;
591}
592
[63783]593/** @copydoc VDIMAGEBACKEND::pfnRead */
[57388]594static DECLCALLBACK(int) parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
595 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
[21371]596{
[44252]597 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
598 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
599 int rc = VINF_SUCCESS;
[32536]600 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[44252]601 uint64_t uSector;
602 uint64_t uOffsetInFile;
603 uint32_t iIndexInAllocationTable;
[21371]604
[32536]605 AssertPtr(pImage);
[21371]606 Assert(uOffset % 512 == 0);
[38413]607 Assert(cbToRead % 512 == 0);
[21371]608
609 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
[44252]610 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
611 pIoCtx, cbToRead);
[21371]612 else
613 {
[30863]614 /* Calculate offset in the real file. */
[21371]615 uSector = uOffset / 512;
[30863]616 /* One chunk in the file is always one track big. */
[21371]617 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
618 uSector = uSector % pImage->PCHSGeometry.cSectors;
619
[38413]620 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
621
[21371]622 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
623 rc = VERR_VD_BLOCK_FREE;
624 else
625 {
[44252]626 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
627 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
628 pIoCtx, cbToRead);
[21371]629 }
630 }
631
[44252]632 *pcbActuallyRead = cbToRead;
[21371]633
634 LogFlowFunc(("returns %Rrc\n", rc));
635 return rc;
636}
637
[63783]638/** @copydoc VDIMAGEBACKEND::pfnWrite */
[57388]639static DECLCALLBACK(int) parallelsWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
640 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
641 size_t *pcbPostRead, unsigned fWrite)
[21371]642{
[44252]643 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
644 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
645 int rc = VINF_SUCCESS;
[32536]646 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[44252]647 uint64_t uSector;
648 uint64_t uOffsetInFile;
649 uint32_t iIndexInAllocationTable;
[21371]650
[32536]651 AssertPtr(pImage);
[21371]652 Assert(uOffset % 512 == 0);
[38413]653 Assert(cbToWrite % 512 == 0);
[21371]654
655 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
[44252]656 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
657 pIoCtx, cbToWrite, NULL, NULL);
[21371]658 else
659 {
[38413]660 /* Calculate offset in the real file. */
[21371]661 uSector = uOffset / 512;
[38413]662 /* One chunk in the file is always one track big. */
[21371]663 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
664 uSector = uSector % pImage->PCHSGeometry.cSectors;
665
[38413]666 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
667
[21371]668 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
669 {
[44252]670 if (fWrite & VD_WRITE_NO_ALLOC)
[38413]671 {
[44252]672 *pcbPreRead = uSector * 512;
673 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
[22966]674
[44252]675 if (pcbWriteProcess)
676 *pcbWriteProcess = cbToWrite;
677 return VERR_VD_BLOCK_FREE;
678 }
[22966]679
[44252]680 /* Allocate new chunk in the file. */
681 Assert(uSector == 0);
682 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
683 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
684 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
685 pImage->fAllocationBitmapChanged = true;
686 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
[38413]687
[44252]688 /*
689 * Write the new block at the current end of the file.
690 */
691 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
692 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
693 if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
[32536]694 {
[44252]695 /* Write the changed allocation bitmap entry. */
[63567]696 /** @todo Error handling. */
[44252]697 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
698 sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
699 &pImage->pAllocationBitmap[iIndexInAllocationTable],
700 sizeof(uint32_t), pIoCtx,
701 NULL, NULL);
[32536]702 }
[44252]703
704 *pcbPreRead = 0;
705 *pcbPostRead = 0;
[21371]706 }
[22966]707 else
708 {
[44252]709 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
710 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
711 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
[22966]712 }
[21371]713 }
714
[32536]715 if (pcbWriteProcess)
[38413]716 *pcbWriteProcess = cbToWrite;
[21371]717
718 LogFlowFunc(("returns %Rrc\n", rc));
719 return rc;
720}
721
[63783]722/** @copydoc VDIMAGEBACKEND::pfnFlush */
[57388]723static DECLCALLBACK(int) parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
[21371]724{
[44252]725 int rc = VINF_SUCCESS;
[21371]726 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
727
[44252]728 LogFlowFunc(("pImage=#%p\n", pImage));
[21371]729
[44252]730 /* Flush the file, everything is up to date already. */
731 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
[21371]732
733 LogFlowFunc(("returns %Rrc\n", rc));
734 return rc;
735}
736
[63783]737/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
[57388]738static DECLCALLBACK(unsigned) parallelsGetVersion(void *pBackendData)
[21371]739{
740 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
741 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
742
[63780]743 AssertPtrReturn(pImage, 0);
[21371]744
[63780]745 return PARALLELS_DISK_VERSION;
[21371]746}
747
[63783]748/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
[57388]749static DECLCALLBACK(uint64_t) parallelsGetFileSize(void *pBackendData)
[21371]750{
751 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
752 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
753 uint64_t cb = 0;
754
[63780]755 AssertPtrReturn(pImage, 0);
[21371]756
[63780]757 if (pImage->pStorage)
[32536]758 cb = pImage->cbFileCurrent;
[21371]759
760 LogFlowFunc(("returns %lld\n", cb));
761 return cb;
762}
763
[63783]764/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
[57388]765static DECLCALLBACK(int) parallelsGetPCHSGeometry(void *pBackendData,
766 PVDGEOMETRY pPCHSGeometry)
[21371]767{
768 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
769 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]770 int rc = VINF_SUCCESS;
[21371]771
[63780]772 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]773
[63780]774 if (pImage->PCHSGeometry.cCylinders)
775 *pPCHSGeometry = pImage->PCHSGeometry;
[21371]776 else
[63780]777 rc = VERR_VD_GEOMETRY_NOT_SET;
[21371]778
779 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
780 return rc;
781}
782
[63783]783/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
[57388]784static DECLCALLBACK(int) parallelsSetPCHSGeometry(void *pBackendData,
785 PCVDGEOMETRY pPCHSGeometry)
[21371]786{
[63780]787 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData,
788 pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
[21371]789 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]790 int rc = VINF_SUCCESS;
[21371]791
[63780]792 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]793
[63780]794 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
795 rc = VERR_VD_IMAGE_READ_ONLY;
796 else
[21371]797 pImage->PCHSGeometry = *pPCHSGeometry;
798
799 LogFlowFunc(("returns %Rrc\n", rc));
800 return rc;
801}
802
[63783]803/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
[57388]804static DECLCALLBACK(int) parallelsGetLCHSGeometry(void *pBackendData,
805 PVDGEOMETRY pLCHSGeometry)
[21371]806{
807 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
808 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]809 int rc = VINF_SUCCESS;
[21371]810
[63780]811 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]812
[63780]813 if (pImage->LCHSGeometry.cCylinders)
814 *pLCHSGeometry = pImage->LCHSGeometry;
[21371]815 else
[63780]816 rc = VERR_VD_GEOMETRY_NOT_SET;
[21371]817
818 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
819 return rc;
820}
821
[63783]822/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
[57388]823static DECLCALLBACK(int) parallelsSetLCHSGeometry(void *pBackendData,
824 PCVDGEOMETRY pLCHSGeometry)
[21371]825{
826 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
827 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]828 int rc = VINF_SUCCESS;
[21371]829
[63780]830 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]831
[63780]832 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
833 rc = VERR_VD_IMAGE_READ_ONLY;
834 else
[21371]835 pImage->LCHSGeometry = *pLCHSGeometry;
836
837 LogFlowFunc(("returns %Rrc\n", rc));
838 return rc;
839}
840
[66486]841/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
842static DECLCALLBACK(int) parallelsQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
843{
844 LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
845 PPARALLELSIMAGE pThis = (PPARALLELSIMAGE)pBackendData;
846
847 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
848
849 *ppRegionList = &pThis->RegionList;
850 LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
851 return VINF_SUCCESS;
852}
853
854/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
855static DECLCALLBACK(void) parallelsRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
856{
857 RT_NOREF1(pRegionList);
858 LogFlowFunc(("pBackendData=%#p pRegionList=%#p\n", pBackendData, pRegionList));
859 PPARALLELSIMAGE pThis = (PPARALLELSIMAGE)pBackendData;
860 AssertPtr(pThis); RT_NOREF(pThis);
861
862 /* Nothing to do here. */
863}
864
[63783]865/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
[57388]866static DECLCALLBACK(unsigned) parallelsGetImageFlags(void *pBackendData)
[21371]867{
868 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
869 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
870
[63780]871 AssertPtrReturn(pImage, 0);
[21371]872
[63780]873 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
874 return pImage->uImageFlags;
[21371]875}
876
[63783]877/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
[57388]878static DECLCALLBACK(unsigned) parallelsGetOpenFlags(void *pBackendData)
[21371]879{
880 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
881 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
882
[63780]883 AssertPtrReturn(pImage, 0);
[21371]884
[63780]885 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
886 return pImage->uOpenFlags;
[21371]887}
888
[63783]889/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
[57388]890static DECLCALLBACK(int) parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
[21371]891{
892 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
893 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
[63780]894 int rc = VINF_SUCCESS;
[21371]895
[33182]896 /* Image must be opened and the new flags must be valid. */
[44232]897 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
898 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
899 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
[63780]900 rc = VERR_INVALID_PARAMETER;
901 else
[21371]902 {
[63780]903 /* Implement this operation via reopening the image. */
904 parallelsFreeImage(pImage, false);
905 rc = parallelsOpenImage(pImage, uOpenFlags);
[21371]906 }
907
908 LogFlowFunc(("returns %Rrc\n", rc));
909 return rc;
910}
911
[63783]912/** @copydoc VDIMAGEBACKEND::pfnGetComment */
[57388]913static DECLCALLBACK(int) parallelsGetComment(void *pBackendData, char *pszComment,
914 size_t cbComment)
[21371]915{
[62751]916 RT_NOREF2(pszComment, cbComment);
[21371]917 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
918 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
919
[63780]920 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]921
[63780]922 LogFlowFunc(("returns %Rrc comment='%s'\n", VERR_NOT_SUPPORTED, pszComment));
923 return VERR_NOT_SUPPORTED;
[21371]924}
925
[63783]926/** @copydoc VDIMAGEBACKEND::pfnSetComment */
[57388]927static DECLCALLBACK(int) parallelsSetComment(void *pBackendData, const char *pszComment)
[21371]928{
[62751]929 RT_NOREF1(pszComment);
[21371]930 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
931 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
932
[63780]933 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]934
[63780]935 int rc;
936 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
937 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]938 else
[63780]939 rc = VERR_NOT_SUPPORTED;
[21371]940
941 LogFlowFunc(("returns %Rrc\n", rc));
942 return rc;
943}
944
[63783]945/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
[57388]946static DECLCALLBACK(int) parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
[21371]947{
[62751]948 RT_NOREF1(pUuid);
[21371]949 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
950 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
951
[63780]952 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]953
[63780]954 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
955 return VERR_NOT_SUPPORTED;
[21371]956}
957
[63783]958/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
[57388]959static DECLCALLBACK(int) parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
[21371]960{
[62751]961 RT_NOREF1(pUuid);
[21371]962 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
963 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
964
[63780]965 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]966
[63780]967 int rc;
968 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
969 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]970 else
[63780]971 rc = VERR_NOT_SUPPORTED;
[21371]972
973 LogFlowFunc(("returns %Rrc\n", rc));
974 return rc;
975}
976
[63783]977/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
[57388]978static DECLCALLBACK(int) parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
[21371]979{
[62751]980 RT_NOREF1(pUuid);
[21371]981 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
982 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
983
[63780]984 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]985
[63780]986 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
987 return VERR_NOT_SUPPORTED;
[21371]988}
989
[63783]990/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
[57388]991static DECLCALLBACK(int) parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
[21371]992{
[62751]993 RT_NOREF1(pUuid);
[21371]994 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
995 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
996
[63780]997 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]998
[63780]999 int rc;
1000 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1001 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]1002 else
[63780]1003 rc = VERR_NOT_SUPPORTED;
[21371]1004
1005 LogFlowFunc(("returns %Rrc\n", rc));
1006 return rc;
1007}
1008
[63783]1009/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
[57388]1010static DECLCALLBACK(int) parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
[21371]1011{
[62751]1012 RT_NOREF1(pUuid);
[21371]1013 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1014 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1015
[63780]1016 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1017
[63780]1018 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
1019 return VERR_NOT_SUPPORTED;
[21371]1020}
1021
[63783]1022/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
[57388]1023static DECLCALLBACK(int) parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
[21371]1024{
[62751]1025 RT_NOREF1(pUuid);
[21371]1026 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1027 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1028
[63780]1029 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1030
[63780]1031 int rc;
1032 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1033 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]1034 else
[63780]1035 rc = VERR_NOT_SUPPORTED;
[21371]1036
1037 LogFlowFunc(("returns %Rrc\n", rc));
1038 return rc;
1039}
1040
[63783]1041/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
[57388]1042static DECLCALLBACK(int) parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
[21371]1043{
[62751]1044 RT_NOREF1(pUuid);
[21371]1045 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1046 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1047
[63780]1048 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1049
[63780]1050 int rc;
1051 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1052 rc = VERR_VD_IMAGE_READ_ONLY;
1053 else
[21371]1054 rc = VERR_NOT_SUPPORTED;
1055
1056 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1057 return rc;
1058}
1059
[63783]1060/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
[57388]1061static DECLCALLBACK(int) parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
[21371]1062{
[62751]1063 RT_NOREF1(pUuid);
[21371]1064 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1065 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1066
[63780]1067 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
[21371]1068
[63780]1069 int rc;
1070 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1071 rc = VERR_VD_IMAGE_READ_ONLY;
[21371]1072 else
[63780]1073 rc = VERR_NOT_SUPPORTED;
[21371]1074
1075 LogFlowFunc(("returns %Rrc\n", rc));
1076 return rc;
1077}
1078
[63783]1079/** @copydoc VDIMAGEBACKEND::pfnDump */
[57388]1080static DECLCALLBACK(void) parallelsDump(void *pBackendData)
[21371]1081{
1082 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1083
[63780]1084 AssertPtrReturnVoid(pImage);
1085 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
1086 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1087 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
[21371]1088}
1089
[30864]1090
1091
[63781]1092const VDIMAGEBACKEND g_ParallelsBackend =
[21371]1093{
[63905]1094 /* u32Version */
1095 VD_IMGBACKEND_VERSION,
[21371]1096 /* pszBackendName */
1097 "Parallels",
1098 /* uBackendCaps */
[38413]1099 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
[33524]1100 /* paFileExtensions */
1101 s_aParallelsFileExtensions,
[21371]1102 /* paConfigInfo */
1103 NULL,
[63802]1104 /* pfnProbe */
1105 parallelsProbe,
[21371]1106 /* pfnOpen */
1107 parallelsOpen,
1108 /* pfnCreate */
1109 parallelsCreate,
1110 /* pfnRename */
1111 parallelsRename,
1112 /* pfnClose */
1113 parallelsClose,
1114 /* pfnRead */
1115 parallelsRead,
1116 /* pfnWrite */
1117 parallelsWrite,
1118 /* pfnFlush */
1119 parallelsFlush,
[44252]1120 /* pfnDiscard */
1121 NULL,
[21371]1122 /* pfnGetVersion */
1123 parallelsGetVersion,
1124 /* pfnGetFileSize */
1125 parallelsGetFileSize,
1126 /* pfnGetPCHSGeometry */
1127 parallelsGetPCHSGeometry,
1128 /* pfnSetPCHSGeometry */
1129 parallelsSetPCHSGeometry,
1130 /* pfnGetLCHSGeometry */
1131 parallelsGetLCHSGeometry,
1132 /* pfnSetLCHSGeometry */
1133 parallelsSetLCHSGeometry,
[66110]1134 /* pfnQueryRegions */
[66486]1135 parallelsQueryRegions,
[66110]1136 /* pfnRegionListRelease */
[66486]1137 parallelsRegionListRelease,
[21371]1138 /* pfnGetImageFlags */
1139 parallelsGetImageFlags,
1140 /* pfnGetOpenFlags */
1141 parallelsGetOpenFlags,
1142 /* pfnSetOpenFlags */
1143 parallelsSetOpenFlags,
1144 /* pfnGetComment */
1145 parallelsGetComment,
1146 /* pfnSetComment */
1147 parallelsSetComment,
1148 /* pfnGetUuid */
1149 parallelsGetUuid,
1150 /* pfnSetUuid */
1151 parallelsSetUuid,
1152 /* pfnGetModificationUuid */
1153 parallelsGetModificationUuid,
1154 /* pfnSetModificationUuid */
1155 parallelsSetModificationUuid,
1156 /* pfnGetParentUuid */
1157 parallelsGetParentUuid,
1158 /* pfnSetParentUuid */
1159 parallelsSetParentUuid,
1160 /* pfnGetParentModificationUuid */
1161 parallelsGetParentModificationUuid,
1162 /* pfnSetParentModificationUuid */
1163 parallelsSetParentModificationUuid,
1164 /* pfnDump */
1165 parallelsDump,
[58132]1166 /* pfnGetTimestamp */
[32536]1167 NULL,
[58132]1168 /* pfnGetParentTimestamp */
[32536]1169 NULL,
[58132]1170 /* pfnSetParentTimestamp */
[32536]1171 NULL,
[21371]1172 /* pfnGetParentFilename */
[32536]1173 NULL,
[21371]1174 /* pfnSetParentFilename */
[32536]1175 NULL,
[21371]1176 /* pfnComposeLocation */
1177 genericFileComposeLocation,
1178 /* pfnComposeName */
[26291]1179 genericFileComposeName,
1180 /* pfnCompact */
[31776]1181 NULL,
1182 /* pfnResize */
[44101]1183 NULL,
1184 /* pfnRepair */
[50988]1185 NULL,
1186 /* pfnTraverseMetadata */
[63905]1187 NULL,
1188 /* u32VersionEnd */
1189 VD_IMGBACKEND_VERSION
[21371]1190};
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