VirtualBox

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

Last change on this file since 81784 was 79965, checked in by vboxsync, 5 years ago

Storage: Added a desired format parameter to VDGetFormat() so Main can pass along the device type. Bumped the RAW backend down after the CUE and VISO to prevent (impossible) mixups of tiny files. Extended rawProbe() to look for a valid ISO-9660/UDF descriptor sequence on the image if the caller doesn't say it should be a floppy or hdd, only if that fail go by the extension. Note! the pfnProbe callback should probably get a score return parameter to indicate how confient the backend is about the probe result, as this would prevent the RAW backend from accidentally grabbing images which belongs to a plug-in. bugref:9151

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.4 KB
Line 
1/* $Id: Parallels.cpp 79965 2019-07-24 20:32:32Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2019 Oracle Corporation
9 *
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.
17 */
18
19#define LOG_GROUP LOG_GROUP_VD_PARALLELS
20#include <VBox/vd-plugin.h>
21#include <VBox/err.h>
22
23#include <VBox/log.h>
24#include <iprt/assert.h>
25#include <iprt/mem.h>
26#include <iprt/uuid.h>
27#include <iprt/path.h>
28#include <iprt/string.h>
29#include <iprt/asm.h>
30
31#include "VDBackends.h"
32
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{
64 /** Image file name. */
65 const char *pszFilename;
66 /** Opaque storage handle. */
67 PVDIOSTORAGE pStorage;
68
69 /** Pointer to the per-disk VD interface list. */
70 PVDINTERFACE pVDIfsDisk;
71 /** Pointer to the per-image VD interface list. */
72 PVDINTERFACE pVDIfsImage;
73 /** Error interface. */
74 PVDINTERFACEERROR pIfError;
75 /** I/O interface. */
76 PVDINTERFACEIOINT pIfIo;
77
78 /** Open flags passed by VBoxHDD layer. */
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;
84
85 /** Physical geometry of this image. */
86 VDGEOMETRY PCHSGeometry;
87 /** Logical geometry of this image. */
88 VDGEOMETRY LCHSGeometry;
89
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;
98 /** The static region list. */
99 VDREGIONLIST RegionList;
100} PARALLELSIMAGE, *PPARALLELSIMAGE;
101
102
103/*********************************************************************************************************************************
104* Static Variables *
105*********************************************************************************************************************************/
106
107/** NULL-terminated array of supported file extensions. */
108static const VDFILEEXTENSION s_aParallelsFileExtensions[] =
109{
110 {"hdd", VDTYPE_HDD},
111 {NULL, VDTYPE_INVALID}
112};
113
114/***************************************************
115 * Internal functions *
116 **************************************************/
117
118/**
119 * Internal. Flush image data to disk.
120 */
121static int parallelsFlushImage(PPARALLELSIMAGE pImage)
122{
123 int rc = VINF_SUCCESS;
124
125 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
126 return VINF_SUCCESS;
127
128 if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
129 && (pImage->fAllocationBitmapChanged))
130 {
131 pImage->fAllocationBitmapChanged = false;
132 /* Write the allocation bitmap to the file. */
133 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
134 sizeof(ParallelsHeader), pImage->pAllocationBitmap,
135 pImage->cAllocationBitmapEntries * sizeof(uint32_t));
136 if (RT_FAILURE(rc))
137 return rc;
138 }
139
140 /* Flush file. */
141 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
142
143 LogFlowFunc(("returns %Rrc\n", rc));
144 return rc;
145}
146
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)
152{
153 int rc = VINF_SUCCESS;
154
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);
164
165 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
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)
176 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
177 }
178
179 return rc;
180}
181
182static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
183{
184 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
185 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
186 pImage->uOpenFlags = uOpenFlags;
187 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
188
189 int rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
190 VDOpenFlagsToFileOpenFlags(uOpenFlags,
191 false /* fCreate */),
192 &pImage->pStorage);
193 if (RT_SUCCESS(rc))
194 {
195 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbFileCurrent);
196 if (RT_SUCCESS(rc)
197 && !(pImage->cbFileCurrent % 512))
198 {
199 ParallelsHeader parallelsHeader;
200
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;
214
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 }
247 }
248 else if (RT_SUCCESS(rc))
249 rc = VERR_VD_PARALLELS_INVALID_HEADER;
250 }
251
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 else
267 parallelsFreeImage(pImage, false);
268
269 LogFlowFunc(("returns %Rrc\n", rc));
270 return rc;
271}
272
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{
283 RT_NOREF1(pszComment);
284 int rc = VINF_SUCCESS;
285 int32_t fOpen;
286
287 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
288 {
289 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
290 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
291 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
292
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 }
304
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);
312
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;
327
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));
336
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);
350 }
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);
353
354 if (RT_SUCCESS(rc) && pfnProgress)
355 pfnProgress(pvUser, uPercentStart + uPercentSpan);
356
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
372 parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
373 return rc;
374}
375
376/** @copydoc VDIMAGEBACKEND::pfnProbe */
377static DECLCALLBACK(int) parallelsProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
378 PVDINTERFACE pVDIfsImage, VDTYPE enmDesiredType, VDTYPE *penmType)
379{
380 RT_NOREF(pVDIfsDisk, enmDesiredType);
381 int rc;
382 PVDIOSTORAGE pStorage;
383 ParallelsHeader parallelsHeader;
384
385 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
386 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
387
388 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
389 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
390 false /* fCreate */),
391 &pStorage);
392 if (RT_FAILURE(rc))
393 return rc;
394
395 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &parallelsHeader,
396 sizeof(ParallelsHeader));
397 if (RT_SUCCESS(rc))
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;
413 char *pszSuffix;
414
415 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
416 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
417 {
418 vdIfIoIntFileClose(pIfIo, pStorage);
419 return VERR_VD_PARALLELS_INVALID_HEADER;
420 }
421
422 pszSuffix = RTPathSuffix(pszFilename);
423 if (!pszSuffix || strcmp(pszSuffix, ".hdd"))
424 rc = VERR_VD_PARALLELS_INVALID_HEADER;
425 else
426 rc = VINF_SUCCESS;
427 }
428 }
429
430 if (RT_SUCCESS(rc))
431 *penmType = VDTYPE_HDD;
432
433 vdIfIoIntFileClose(pIfIo, pStorage);
434 return rc;
435}
436
437/** @copydoc VDIMAGEBACKEND::pfnOpen */
438static DECLCALLBACK(int) parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
439 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
440 VDTYPE enmType, void **ppBackendData)
441{
442 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
443 int rc;
444 PPARALLELSIMAGE pImage;
445
446 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
447
448 /* Check parameters. */
449 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
450 AssertReturn(VALID_PTR(pszFilename) && *pszFilename, VERR_INVALID_PARAMETER);
451
452 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
453 if (RT_LIKELY(pImage))
454 {
455 pImage->pszFilename = pszFilename;
456 pImage->pStorage = NULL;
457 pImage->pVDIfsDisk = pVDIfsDisk;
458 pImage->pVDIfsImage = pVDIfsImage;
459 pImage->fAllocationBitmapChanged = false;
460
461 rc = parallelsOpenImage(pImage, uOpenFlags);
462 if (RT_SUCCESS(rc))
463 *ppBackendData = pImage;
464 else
465 RTMemFree(pImage);
466 }
467 else
468 rc = VERR_NO_MEMORY;
469
470 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
471 return rc;
472}
473
474/** @copydoc VDIMAGEBACKEND::pfnCreate */
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)
484{
485 RT_NOREF1(pUuid);
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));
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
500 int rc = VINF_SUCCESS;
501 PPARALLELSIMAGE pImage;
502 PFNVDPROGRESS pfnProgress = NULL;
503 void *pvUser = NULL;
504 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
505 if (pIfProgress)
506 {
507 pfnProgress = pIfProgress->pfnProgress;
508 pvUser = pIfProgress->Core.pvUser;
509 }
510
511 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
512 if (RT_LIKELY(pImage))
513 {
514 pImage->pszFilename = pszFilename;
515 pImage->pStorage = NULL;
516 pImage->pVDIfsDisk = pVDIfsDisk;
517 pImage->pVDIfsImage = pVDIfsImage;
518
519 rc = parallelsCreateImage(pImage, cbSize, uImageFlags, pszComment,
520 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
521 pfnProgress, pvUser, uPercentStart, uPercentSpan);
522 if (RT_SUCCESS(rc))
523 {
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)
527 {
528 parallelsFreeImage(pImage, false);
529 rc = parallelsOpenImage(pImage, uOpenFlags);
530 }
531
532 if (RT_SUCCESS(rc))
533 *ppBackendData = pImage;
534 }
535
536 if (RT_FAILURE(rc))
537 RTMemFree(pImage);
538 }
539 else
540 rc = VERR_NO_MEMORY;
541
542 LogFlowFunc(("returns %Rrc\n", rc));
543 return rc;
544}
545
546/** @copydoc VDIMAGEBACKEND::pfnRename */
547static DECLCALLBACK(int) parallelsRename(void *pBackendData, const char *pszFilename)
548{
549 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
550 int rc = VINF_SUCCESS;
551 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
552
553 /* Check arguments. */
554 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
555
556 /* Close the image. */
557 rc = parallelsFreeImage(pImage, false);
558 if (RT_SUCCESS(rc))
559 {
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;
566
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 }
577 }
578
579 LogFlowFunc(("returns %Rrc\n", rc));
580 return rc;
581}
582
583/** @copydoc VDIMAGEBACKEND::pfnClose */
584static DECLCALLBACK(int) parallelsClose(void *pBackendData, bool fDelete)
585{
586 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
587 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
588 int rc = parallelsFreeImage(pImage, fDelete);
589 RTMemFree(pImage);
590
591 LogFlowFunc(("returns %Rrc\n", rc));
592 return rc;
593}
594
595/** @copydoc VDIMAGEBACKEND::pfnRead */
596static DECLCALLBACK(int) parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
597 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
598{
599 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
600 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
601 int rc = VINF_SUCCESS;
602 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
603 uint64_t uSector;
604 uint64_t uOffsetInFile;
605 uint32_t iIndexInAllocationTable;
606
607 AssertPtr(pImage);
608 Assert(uOffset % 512 == 0);
609 Assert(cbToRead % 512 == 0);
610
611 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
612 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
613 pIoCtx, cbToRead);
614 else
615 {
616 /* Calculate offset in the real file. */
617 uSector = uOffset / 512;
618 /* One chunk in the file is always one track big. */
619 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
620 uSector = uSector % pImage->PCHSGeometry.cSectors;
621
622 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
623
624 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
625 rc = VERR_VD_BLOCK_FREE;
626 else
627 {
628 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
629 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
630 pIoCtx, cbToRead);
631 }
632 }
633
634 *pcbActuallyRead = cbToRead;
635
636 LogFlowFunc(("returns %Rrc\n", rc));
637 return rc;
638}
639
640/** @copydoc VDIMAGEBACKEND::pfnWrite */
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)
644{
645 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
646 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
647 int rc = VINF_SUCCESS;
648 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
649 uint64_t uSector;
650 uint64_t uOffsetInFile;
651 uint32_t iIndexInAllocationTable;
652
653 AssertPtr(pImage);
654 Assert(uOffset % 512 == 0);
655 Assert(cbToWrite % 512 == 0);
656
657 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
658 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
659 pIoCtx, cbToWrite, NULL, NULL);
660 else
661 {
662 /* Calculate offset in the real file. */
663 uSector = uOffset / 512;
664 /* One chunk in the file is always one track big. */
665 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
666 uSector = uSector % pImage->PCHSGeometry.cSectors;
667
668 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
669
670 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
671 {
672 if (fWrite & VD_WRITE_NO_ALLOC)
673 {
674 *pcbPreRead = uSector * 512;
675 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
676
677 if (pcbWriteProcess)
678 *pcbWriteProcess = cbToWrite;
679 return VERR_VD_BLOCK_FREE;
680 }
681
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;
689
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))
696 {
697 /* Write the changed allocation bitmap entry. */
698 /** @todo Error handling. */
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);
704 }
705
706 *pcbPreRead = 0;
707 *pcbPostRead = 0;
708 }
709 else
710 {
711 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
712 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
713 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
714 }
715 }
716
717 if (pcbWriteProcess)
718 *pcbWriteProcess = cbToWrite;
719
720 LogFlowFunc(("returns %Rrc\n", rc));
721 return rc;
722}
723
724/** @copydoc VDIMAGEBACKEND::pfnFlush */
725static DECLCALLBACK(int) parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
726{
727 int rc = VINF_SUCCESS;
728 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
729
730 LogFlowFunc(("pImage=#%p\n", pImage));
731
732 /* Flush the file, everything is up to date already. */
733 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
734
735 LogFlowFunc(("returns %Rrc\n", rc));
736 return rc;
737}
738
739/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
740static DECLCALLBACK(unsigned) parallelsGetVersion(void *pBackendData)
741{
742 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
743 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
744
745 AssertPtrReturn(pImage, 0);
746
747 return PARALLELS_DISK_VERSION;
748}
749
750/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
751static DECLCALLBACK(uint64_t) parallelsGetFileSize(void *pBackendData)
752{
753 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
754 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
755 uint64_t cb = 0;
756
757 AssertPtrReturn(pImage, 0);
758
759 if (pImage->pStorage)
760 cb = pImage->cbFileCurrent;
761
762 LogFlowFunc(("returns %lld\n", cb));
763 return cb;
764}
765
766/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
767static DECLCALLBACK(int) parallelsGetPCHSGeometry(void *pBackendData,
768 PVDGEOMETRY pPCHSGeometry)
769{
770 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
771 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
772 int rc = VINF_SUCCESS;
773
774 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
775
776 if (pImage->PCHSGeometry.cCylinders)
777 *pPCHSGeometry = pImage->PCHSGeometry;
778 else
779 rc = VERR_VD_GEOMETRY_NOT_SET;
780
781 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
782 return rc;
783}
784
785/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
786static DECLCALLBACK(int) parallelsSetPCHSGeometry(void *pBackendData,
787 PCVDGEOMETRY pPCHSGeometry)
788{
789 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData,
790 pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
791 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
792 int rc = VINF_SUCCESS;
793
794 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
795
796 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
797 rc = VERR_VD_IMAGE_READ_ONLY;
798 else
799 pImage->PCHSGeometry = *pPCHSGeometry;
800
801 LogFlowFunc(("returns %Rrc\n", rc));
802 return rc;
803}
804
805/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
806static DECLCALLBACK(int) parallelsGetLCHSGeometry(void *pBackendData,
807 PVDGEOMETRY pLCHSGeometry)
808{
809 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
810 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
811 int rc = VINF_SUCCESS;
812
813 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
814
815 if (pImage->LCHSGeometry.cCylinders)
816 *pLCHSGeometry = pImage->LCHSGeometry;
817 else
818 rc = VERR_VD_GEOMETRY_NOT_SET;
819
820 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
821 return rc;
822}
823
824/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
825static DECLCALLBACK(int) parallelsSetLCHSGeometry(void *pBackendData,
826 PCVDGEOMETRY pLCHSGeometry)
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;
830 int rc = VINF_SUCCESS;
831
832 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
833
834 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
835 rc = VERR_VD_IMAGE_READ_ONLY;
836 else
837 pImage->LCHSGeometry = *pLCHSGeometry;
838
839 LogFlowFunc(("returns %Rrc\n", rc));
840 return rc;
841}
842
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
867/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
868static DECLCALLBACK(unsigned) parallelsGetImageFlags(void *pBackendData)
869{
870 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
871 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
872
873 AssertPtrReturn(pImage, 0);
874
875 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
876 return pImage->uImageFlags;
877}
878
879/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
880static DECLCALLBACK(unsigned) parallelsGetOpenFlags(void *pBackendData)
881{
882 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
883 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
884
885 AssertPtrReturn(pImage, 0);
886
887 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
888 return pImage->uOpenFlags;
889}
890
891/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
892static DECLCALLBACK(int) parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
893{
894 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
895 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
896 int rc = VINF_SUCCESS;
897
898 /* Image must be opened and the new flags must be valid. */
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)))
902 rc = VERR_INVALID_PARAMETER;
903 else
904 {
905 /* Implement this operation via reopening the image. */
906 parallelsFreeImage(pImage, false);
907 rc = parallelsOpenImage(pImage, uOpenFlags);
908 }
909
910 LogFlowFunc(("returns %Rrc\n", rc));
911 return rc;
912}
913
914/** @copydoc VDIMAGEBACKEND::pfnGetComment */
915static DECLCALLBACK(int) parallelsGetComment(void *pBackendData, char *pszComment,
916 size_t cbComment)
917{
918 RT_NOREF2(pszComment, cbComment);
919 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
920 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
921
922 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
923
924 LogFlowFunc(("returns %Rrc comment='%s'\n", VERR_NOT_SUPPORTED, pszComment));
925 return VERR_NOT_SUPPORTED;
926}
927
928/** @copydoc VDIMAGEBACKEND::pfnSetComment */
929static DECLCALLBACK(int) parallelsSetComment(void *pBackendData, const char *pszComment)
930{
931 RT_NOREF1(pszComment);
932 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
933 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
934
935 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
936
937 int rc;
938 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
939 rc = VERR_VD_IMAGE_READ_ONLY;
940 else
941 rc = VERR_NOT_SUPPORTED;
942
943 LogFlowFunc(("returns %Rrc\n", rc));
944 return rc;
945}
946
947/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
948static DECLCALLBACK(int) parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
949{
950 RT_NOREF1(pUuid);
951 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
952 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
953
954 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
955
956 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
957 return VERR_NOT_SUPPORTED;
958}
959
960/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
961static DECLCALLBACK(int) parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
962{
963 RT_NOREF1(pUuid);
964 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
965 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
966
967 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
968
969 int rc;
970 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
971 rc = VERR_VD_IMAGE_READ_ONLY;
972 else
973 rc = VERR_NOT_SUPPORTED;
974
975 LogFlowFunc(("returns %Rrc\n", rc));
976 return rc;
977}
978
979/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
980static DECLCALLBACK(int) parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
981{
982 RT_NOREF1(pUuid);
983 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
984 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
985
986 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
987
988 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
989 return VERR_NOT_SUPPORTED;
990}
991
992/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
993static DECLCALLBACK(int) parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
994{
995 RT_NOREF1(pUuid);
996 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
997 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
998
999 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1000
1001 int rc;
1002 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1003 rc = VERR_VD_IMAGE_READ_ONLY;
1004 else
1005 rc = VERR_NOT_SUPPORTED;
1006
1007 LogFlowFunc(("returns %Rrc\n", rc));
1008 return rc;
1009}
1010
1011/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
1012static DECLCALLBACK(int) parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
1013{
1014 RT_NOREF1(pUuid);
1015 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1016 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1017
1018 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1019
1020 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
1021 return VERR_NOT_SUPPORTED;
1022}
1023
1024/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
1025static DECLCALLBACK(int) parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1026{
1027 RT_NOREF1(pUuid);
1028 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1029 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1030
1031 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1032
1033 int rc;
1034 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1035 rc = VERR_VD_IMAGE_READ_ONLY;
1036 else
1037 rc = VERR_NOT_SUPPORTED;
1038
1039 LogFlowFunc(("returns %Rrc\n", rc));
1040 return rc;
1041}
1042
1043/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
1044static DECLCALLBACK(int) parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1045{
1046 RT_NOREF1(pUuid);
1047 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1048 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1049
1050 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1051
1052 int rc;
1053 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1054 rc = VERR_VD_IMAGE_READ_ONLY;
1055 else
1056 rc = VERR_NOT_SUPPORTED;
1057
1058 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1059 return rc;
1060}
1061
1062/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
1063static DECLCALLBACK(int) parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1064{
1065 RT_NOREF1(pUuid);
1066 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1067 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1068
1069 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1070
1071 int rc;
1072 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1073 rc = VERR_VD_IMAGE_READ_ONLY;
1074 else
1075 rc = VERR_NOT_SUPPORTED;
1076
1077 LogFlowFunc(("returns %Rrc\n", rc));
1078 return rc;
1079}
1080
1081/** @copydoc VDIMAGEBACKEND::pfnDump */
1082static DECLCALLBACK(void) parallelsDump(void *pBackendData)
1083{
1084 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1085
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);
1090}
1091
1092
1093
1094const VDIMAGEBACKEND g_ParallelsBackend =
1095{
1096 /* u32Version */
1097 VD_IMGBACKEND_VERSION,
1098 /* pszBackendName */
1099 "Parallels",
1100 /* uBackendCaps */
1101 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
1102 /* paFileExtensions */
1103 s_aParallelsFileExtensions,
1104 /* paConfigInfo */
1105 NULL,
1106 /* pfnProbe */
1107 parallelsProbe,
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,
1122 /* pfnDiscard */
1123 NULL,
1124 /* pfnGetVersion */
1125 parallelsGetVersion,
1126 /* pfnGetFileSize */
1127 parallelsGetFileSize,
1128 /* pfnGetPCHSGeometry */
1129 parallelsGetPCHSGeometry,
1130 /* pfnSetPCHSGeometry */
1131 parallelsSetPCHSGeometry,
1132 /* pfnGetLCHSGeometry */
1133 parallelsGetLCHSGeometry,
1134 /* pfnSetLCHSGeometry */
1135 parallelsSetLCHSGeometry,
1136 /* pfnQueryRegions */
1137 parallelsQueryRegions,
1138 /* pfnRegionListRelease */
1139 parallelsRegionListRelease,
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,
1168 /* pfnGetTimestamp */
1169 NULL,
1170 /* pfnGetParentTimestamp */
1171 NULL,
1172 /* pfnSetParentTimestamp */
1173 NULL,
1174 /* pfnGetParentFilename */
1175 NULL,
1176 /* pfnSetParentFilename */
1177 NULL,
1178 /* pfnComposeLocation */
1179 genericFileComposeLocation,
1180 /* pfnComposeName */
1181 genericFileComposeName,
1182 /* pfnCompact */
1183 NULL,
1184 /* pfnResize */
1185 NULL,
1186 /* pfnRepair */
1187 NULL,
1188 /* pfnTraverseMetadata */
1189 NULL,
1190 /* u32VersionEnd */
1191 VD_IMGBACKEND_VERSION
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