VirtualBox

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

Last change on this file since 86186 was 82968, checked in by vboxsync, 5 years 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.4 KB
Line 
1/* $Id: Parallels.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2020 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