VirtualBox

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

Last change on this file since 103131 was 98103, checked in by vboxsync, 20 months ago

Copyright year updates by scm.

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

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use