VirtualBox

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

Last change on this file since 74897 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.3 KB
Line 
1/* $Id: Parallels.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2017 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
267 LogFlowFunc(("returns %Rrc\n", rc));
268 return rc;
269}
270
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{
281 RT_NOREF1(pszComment);
282 int rc = VINF_SUCCESS;
283 int32_t fOpen;
284
285 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
286 {
287 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
288 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
289 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
290
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 }
302
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);
310
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;
325
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));
334
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);
348 }
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);
351
352 if (RT_SUCCESS(rc) && pfnProgress)
353 pfnProgress(pvUser, uPercentStart + uPercentSpan);
354
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
370 parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
371 return rc;
372}
373
374/** @copydoc VDIMAGEBACKEND::pfnProbe */
375static DECLCALLBACK(int) parallelsProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
376 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
377{
378 RT_NOREF1(pVDIfsDisk);
379 int rc;
380 PVDIOSTORAGE pStorage;
381 ParallelsHeader parallelsHeader;
382
383 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
384 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
385
386 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
387 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
388 false /* fCreate */),
389 &pStorage);
390 if (RT_FAILURE(rc))
391 return rc;
392
393 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &parallelsHeader,
394 sizeof(ParallelsHeader));
395 if (RT_SUCCESS(rc))
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;
411 char *pszSuffix;
412
413 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
414 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
415 {
416 vdIfIoIntFileClose(pIfIo, pStorage);
417 return VERR_VD_PARALLELS_INVALID_HEADER;
418 }
419
420 pszSuffix = RTPathSuffix(pszFilename);
421 if (!pszSuffix || strcmp(pszSuffix, ".hdd"))
422 rc = VERR_VD_PARALLELS_INVALID_HEADER;
423 else
424 rc = VINF_SUCCESS;
425 }
426 }
427
428 if (RT_SUCCESS(rc))
429 *penmType = VDTYPE_HDD;
430
431 vdIfIoIntFileClose(pIfIo, pStorage);
432 return rc;
433}
434
435/** @copydoc VDIMAGEBACKEND::pfnOpen */
436static DECLCALLBACK(int) parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
437 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
438 VDTYPE enmType, void **ppBackendData)
439{
440 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
441 int rc;
442 PPARALLELSIMAGE pImage;
443
444 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
445
446 /* Check parameters. */
447 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
448 AssertReturn(VALID_PTR(pszFilename) && *pszFilename, VERR_INVALID_PARAMETER);
449
450 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
451 if (RT_LIKELY(pImage))
452 {
453 pImage->pszFilename = pszFilename;
454 pImage->pStorage = NULL;
455 pImage->pVDIfsDisk = pVDIfsDisk;
456 pImage->pVDIfsImage = pVDIfsImage;
457 pImage->fAllocationBitmapChanged = false;
458
459 rc = parallelsOpenImage(pImage, uOpenFlags);
460 if (RT_SUCCESS(rc))
461 *ppBackendData = pImage;
462 else
463 RTMemFree(pImage);
464 }
465 else
466 rc = VERR_NO_MEMORY;
467
468 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
469 return rc;
470}
471
472/** @copydoc VDIMAGEBACKEND::pfnCreate */
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)
482{
483 RT_NOREF1(pUuid);
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));
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
498 int rc = VINF_SUCCESS;
499 PPARALLELSIMAGE pImage;
500 PFNVDPROGRESS pfnProgress = NULL;
501 void *pvUser = NULL;
502 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
503 if (pIfProgress)
504 {
505 pfnProgress = pIfProgress->pfnProgress;
506 pvUser = pIfProgress->Core.pvUser;
507 }
508
509 pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
510 if (RT_LIKELY(pImage))
511 {
512 pImage->pszFilename = pszFilename;
513 pImage->pStorage = NULL;
514 pImage->pVDIfsDisk = pVDIfsDisk;
515 pImage->pVDIfsImage = pVDIfsImage;
516
517 rc = parallelsCreateImage(pImage, cbSize, uImageFlags, pszComment,
518 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
519 pfnProgress, pvUser, uPercentStart, uPercentSpan);
520 if (RT_SUCCESS(rc))
521 {
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)
525 {
526 parallelsFreeImage(pImage, false);
527 rc = parallelsOpenImage(pImage, uOpenFlags);
528 }
529
530 if (RT_SUCCESS(rc))
531 *ppBackendData = pImage;
532 }
533
534 if (RT_FAILURE(rc))
535 RTMemFree(pImage);
536 }
537 else
538 rc = VERR_NO_MEMORY;
539
540 LogFlowFunc(("returns %Rrc\n", rc));
541 return rc;
542}
543
544/** @copydoc VDIMAGEBACKEND::pfnRename */
545static DECLCALLBACK(int) parallelsRename(void *pBackendData, const char *pszFilename)
546{
547 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
548 int rc = VINF_SUCCESS;
549 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
550
551 /* Check arguments. */
552 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
553
554 /* Close the image. */
555 rc = parallelsFreeImage(pImage, false);
556 if (RT_SUCCESS(rc))
557 {
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;
564
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 }
575 }
576
577 LogFlowFunc(("returns %Rrc\n", rc));
578 return rc;
579}
580
581/** @copydoc VDIMAGEBACKEND::pfnClose */
582static DECLCALLBACK(int) parallelsClose(void *pBackendData, bool fDelete)
583{
584 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
585 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
586 int rc = parallelsFreeImage(pImage, fDelete);
587 RTMemFree(pImage);
588
589 LogFlowFunc(("returns %Rrc\n", rc));
590 return rc;
591}
592
593/** @copydoc VDIMAGEBACKEND::pfnRead */
594static DECLCALLBACK(int) parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
595 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
596{
597 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
598 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
599 int rc = VINF_SUCCESS;
600 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
601 uint64_t uSector;
602 uint64_t uOffsetInFile;
603 uint32_t iIndexInAllocationTable;
604
605 AssertPtr(pImage);
606 Assert(uOffset % 512 == 0);
607 Assert(cbToRead % 512 == 0);
608
609 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
610 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
611 pIoCtx, cbToRead);
612 else
613 {
614 /* Calculate offset in the real file. */
615 uSector = uOffset / 512;
616 /* One chunk in the file is always one track big. */
617 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
618 uSector = uSector % pImage->PCHSGeometry.cSectors;
619
620 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
621
622 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
623 rc = VERR_VD_BLOCK_FREE;
624 else
625 {
626 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
627 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
628 pIoCtx, cbToRead);
629 }
630 }
631
632 *pcbActuallyRead = cbToRead;
633
634 LogFlowFunc(("returns %Rrc\n", rc));
635 return rc;
636}
637
638/** @copydoc VDIMAGEBACKEND::pfnWrite */
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)
642{
643 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
644 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
645 int rc = VINF_SUCCESS;
646 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
647 uint64_t uSector;
648 uint64_t uOffsetInFile;
649 uint32_t iIndexInAllocationTable;
650
651 AssertPtr(pImage);
652 Assert(uOffset % 512 == 0);
653 Assert(cbToWrite % 512 == 0);
654
655 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
656 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
657 pIoCtx, cbToWrite, NULL, NULL);
658 else
659 {
660 /* Calculate offset in the real file. */
661 uSector = uOffset / 512;
662 /* One chunk in the file is always one track big. */
663 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
664 uSector = uSector % pImage->PCHSGeometry.cSectors;
665
666 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
667
668 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
669 {
670 if (fWrite & VD_WRITE_NO_ALLOC)
671 {
672 *pcbPreRead = uSector * 512;
673 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
674
675 if (pcbWriteProcess)
676 *pcbWriteProcess = cbToWrite;
677 return VERR_VD_BLOCK_FREE;
678 }
679
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;
687
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))
694 {
695 /* Write the changed allocation bitmap entry. */
696 /** @todo Error handling. */
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);
702 }
703
704 *pcbPreRead = 0;
705 *pcbPostRead = 0;
706 }
707 else
708 {
709 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
710 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
711 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
712 }
713 }
714
715 if (pcbWriteProcess)
716 *pcbWriteProcess = cbToWrite;
717
718 LogFlowFunc(("returns %Rrc\n", rc));
719 return rc;
720}
721
722/** @copydoc VDIMAGEBACKEND::pfnFlush */
723static DECLCALLBACK(int) parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
724{
725 int rc = VINF_SUCCESS;
726 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
727
728 LogFlowFunc(("pImage=#%p\n", pImage));
729
730 /* Flush the file, everything is up to date already. */
731 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
732
733 LogFlowFunc(("returns %Rrc\n", rc));
734 return rc;
735}
736
737/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
738static DECLCALLBACK(unsigned) parallelsGetVersion(void *pBackendData)
739{
740 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
741 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
742
743 AssertPtrReturn(pImage, 0);
744
745 return PARALLELS_DISK_VERSION;
746}
747
748/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
749static DECLCALLBACK(uint64_t) parallelsGetFileSize(void *pBackendData)
750{
751 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
752 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
753 uint64_t cb = 0;
754
755 AssertPtrReturn(pImage, 0);
756
757 if (pImage->pStorage)
758 cb = pImage->cbFileCurrent;
759
760 LogFlowFunc(("returns %lld\n", cb));
761 return cb;
762}
763
764/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
765static DECLCALLBACK(int) parallelsGetPCHSGeometry(void *pBackendData,
766 PVDGEOMETRY pPCHSGeometry)
767{
768 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
769 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
770 int rc = VINF_SUCCESS;
771
772 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
773
774 if (pImage->PCHSGeometry.cCylinders)
775 *pPCHSGeometry = pImage->PCHSGeometry;
776 else
777 rc = VERR_VD_GEOMETRY_NOT_SET;
778
779 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
780 return rc;
781}
782
783/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
784static DECLCALLBACK(int) parallelsSetPCHSGeometry(void *pBackendData,
785 PCVDGEOMETRY pPCHSGeometry)
786{
787 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData,
788 pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
789 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
790 int rc = VINF_SUCCESS;
791
792 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
793
794 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
795 rc = VERR_VD_IMAGE_READ_ONLY;
796 else
797 pImage->PCHSGeometry = *pPCHSGeometry;
798
799 LogFlowFunc(("returns %Rrc\n", rc));
800 return rc;
801}
802
803/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
804static DECLCALLBACK(int) parallelsGetLCHSGeometry(void *pBackendData,
805 PVDGEOMETRY pLCHSGeometry)
806{
807 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
808 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
809 int rc = VINF_SUCCESS;
810
811 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
812
813 if (pImage->LCHSGeometry.cCylinders)
814 *pLCHSGeometry = pImage->LCHSGeometry;
815 else
816 rc = VERR_VD_GEOMETRY_NOT_SET;
817
818 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
819 return rc;
820}
821
822/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
823static DECLCALLBACK(int) parallelsSetLCHSGeometry(void *pBackendData,
824 PCVDGEOMETRY pLCHSGeometry)
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;
828 int rc = VINF_SUCCESS;
829
830 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
831
832 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
833 rc = VERR_VD_IMAGE_READ_ONLY;
834 else
835 pImage->LCHSGeometry = *pLCHSGeometry;
836
837 LogFlowFunc(("returns %Rrc\n", rc));
838 return rc;
839}
840
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
865/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
866static DECLCALLBACK(unsigned) parallelsGetImageFlags(void *pBackendData)
867{
868 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
869 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
870
871 AssertPtrReturn(pImage, 0);
872
873 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
874 return pImage->uImageFlags;
875}
876
877/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
878static DECLCALLBACK(unsigned) parallelsGetOpenFlags(void *pBackendData)
879{
880 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
881 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
882
883 AssertPtrReturn(pImage, 0);
884
885 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
886 return pImage->uOpenFlags;
887}
888
889/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
890static DECLCALLBACK(int) parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
891{
892 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
893 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
894 int rc = VINF_SUCCESS;
895
896 /* Image must be opened and the new flags must be valid. */
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)))
900 rc = VERR_INVALID_PARAMETER;
901 else
902 {
903 /* Implement this operation via reopening the image. */
904 parallelsFreeImage(pImage, false);
905 rc = parallelsOpenImage(pImage, uOpenFlags);
906 }
907
908 LogFlowFunc(("returns %Rrc\n", rc));
909 return rc;
910}
911
912/** @copydoc VDIMAGEBACKEND::pfnGetComment */
913static DECLCALLBACK(int) parallelsGetComment(void *pBackendData, char *pszComment,
914 size_t cbComment)
915{
916 RT_NOREF2(pszComment, cbComment);
917 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
918 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
919
920 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
921
922 LogFlowFunc(("returns %Rrc comment='%s'\n", VERR_NOT_SUPPORTED, pszComment));
923 return VERR_NOT_SUPPORTED;
924}
925
926/** @copydoc VDIMAGEBACKEND::pfnSetComment */
927static DECLCALLBACK(int) parallelsSetComment(void *pBackendData, const char *pszComment)
928{
929 RT_NOREF1(pszComment);
930 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
931 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
932
933 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
934
935 int rc;
936 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
937 rc = VERR_VD_IMAGE_READ_ONLY;
938 else
939 rc = VERR_NOT_SUPPORTED;
940
941 LogFlowFunc(("returns %Rrc\n", rc));
942 return rc;
943}
944
945/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
946static DECLCALLBACK(int) parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
947{
948 RT_NOREF1(pUuid);
949 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
950 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
951
952 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
953
954 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
955 return VERR_NOT_SUPPORTED;
956}
957
958/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
959static DECLCALLBACK(int) parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
960{
961 RT_NOREF1(pUuid);
962 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
963 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
964
965 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
966
967 int rc;
968 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
969 rc = VERR_VD_IMAGE_READ_ONLY;
970 else
971 rc = VERR_NOT_SUPPORTED;
972
973 LogFlowFunc(("returns %Rrc\n", rc));
974 return rc;
975}
976
977/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
978static DECLCALLBACK(int) parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
979{
980 RT_NOREF1(pUuid);
981 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
982 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
983
984 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
985
986 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
987 return VERR_NOT_SUPPORTED;
988}
989
990/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
991static DECLCALLBACK(int) parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
992{
993 RT_NOREF1(pUuid);
994 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
995 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
996
997 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
998
999 int rc;
1000 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1001 rc = VERR_VD_IMAGE_READ_ONLY;
1002 else
1003 rc = VERR_NOT_SUPPORTED;
1004
1005 LogFlowFunc(("returns %Rrc\n", rc));
1006 return rc;
1007}
1008
1009/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
1010static DECLCALLBACK(int) parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
1011{
1012 RT_NOREF1(pUuid);
1013 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1014 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1015
1016 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1017
1018 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
1019 return VERR_NOT_SUPPORTED;
1020}
1021
1022/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
1023static DECLCALLBACK(int) parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1024{
1025 RT_NOREF1(pUuid);
1026 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1027 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1028
1029 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1030
1031 int rc;
1032 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1033 rc = VERR_VD_IMAGE_READ_ONLY;
1034 else
1035 rc = VERR_NOT_SUPPORTED;
1036
1037 LogFlowFunc(("returns %Rrc\n", rc));
1038 return rc;
1039}
1040
1041/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
1042static DECLCALLBACK(int) parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1043{
1044 RT_NOREF1(pUuid);
1045 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1046 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1047
1048 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1049
1050 int rc;
1051 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1052 rc = VERR_VD_IMAGE_READ_ONLY;
1053 else
1054 rc = VERR_NOT_SUPPORTED;
1055
1056 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1057 return rc;
1058}
1059
1060/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
1061static DECLCALLBACK(int) parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1062{
1063 RT_NOREF1(pUuid);
1064 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1065 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1066
1067 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1068
1069 int rc;
1070 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1071 rc = VERR_VD_IMAGE_READ_ONLY;
1072 else
1073 rc = VERR_NOT_SUPPORTED;
1074
1075 LogFlowFunc(("returns %Rrc\n", rc));
1076 return rc;
1077}
1078
1079/** @copydoc VDIMAGEBACKEND::pfnDump */
1080static DECLCALLBACK(void) parallelsDump(void *pBackendData)
1081{
1082 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1083
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);
1088}
1089
1090
1091
1092const VDIMAGEBACKEND g_ParallelsBackend =
1093{
1094 /* u32Version */
1095 VD_IMGBACKEND_VERSION,
1096 /* pszBackendName */
1097 "Parallels",
1098 /* uBackendCaps */
1099 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
1100 /* paFileExtensions */
1101 s_aParallelsFileExtensions,
1102 /* paConfigInfo */
1103 NULL,
1104 /* pfnProbe */
1105 parallelsProbe,
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,
1120 /* pfnDiscard */
1121 NULL,
1122 /* pfnGetVersion */
1123 parallelsGetVersion,
1124 /* pfnGetFileSize */
1125 parallelsGetFileSize,
1126 /* pfnGetPCHSGeometry */
1127 parallelsGetPCHSGeometry,
1128 /* pfnSetPCHSGeometry */
1129 parallelsSetPCHSGeometry,
1130 /* pfnGetLCHSGeometry */
1131 parallelsGetLCHSGeometry,
1132 /* pfnSetLCHSGeometry */
1133 parallelsSetLCHSGeometry,
1134 /* pfnQueryRegions */
1135 parallelsQueryRegions,
1136 /* pfnRegionListRelease */
1137 parallelsRegionListRelease,
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,
1166 /* pfnGetTimestamp */
1167 NULL,
1168 /* pfnGetParentTimestamp */
1169 NULL,
1170 /* pfnSetParentTimestamp */
1171 NULL,
1172 /* pfnGetParentFilename */
1173 NULL,
1174 /* pfnSetParentFilename */
1175 NULL,
1176 /* pfnComposeLocation */
1177 genericFileComposeLocation,
1178 /* pfnComposeName */
1179 genericFileComposeName,
1180 /* pfnCompact */
1181 NULL,
1182 /* pfnResize */
1183 NULL,
1184 /* pfnRepair */
1185 NULL,
1186 /* pfnTraverseMetadata */
1187 NULL,
1188 /* u32VersionEnd */
1189 VD_IMGBACKEND_VERSION
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