VirtualBox

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

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

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.2 KB
Line 
1/* $Id: Parallels.cpp 62482 2016-07-22 18:30:37Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2016 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} PARALLELSIMAGE, *PPARALLELSIMAGE;
99
100
101/*********************************************************************************************************************************
102* Static Variables *
103*********************************************************************************************************************************/
104
105/** NULL-terminated array of supported file extensions. */
106static const VDFILEEXTENSION s_aParallelsFileExtensions[] =
107{
108 {"hdd", VDTYPE_HDD},
109 {NULL, VDTYPE_INVALID}
110};
111
112/***************************************************
113 * Internal functions *
114 **************************************************/
115
116/**
117 * Internal. Flush image data to disk.
118 */
119static int parallelsFlushImage(PPARALLELSIMAGE pImage)
120{
121 int rc = VINF_SUCCESS;
122
123 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
124 return VINF_SUCCESS;
125
126 if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
127 && (pImage->fAllocationBitmapChanged))
128 {
129 pImage->fAllocationBitmapChanged = false;
130 /* Write the allocation bitmap to the file. */
131 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
132 sizeof(ParallelsHeader), pImage->pAllocationBitmap,
133 pImage->cAllocationBitmapEntries * sizeof(uint32_t));
134 if (RT_FAILURE(rc))
135 return rc;
136 }
137
138 /* Flush file. */
139 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
140
141 LogFlowFunc(("returns %Rrc\n", rc));
142 return rc;
143}
144
145/**
146 * Internal. Free all allocated space for representing an image except pImage,
147 * and optionally delete the image from disk.
148 */
149static int parallelsFreeImage(PPARALLELSIMAGE pImage, bool fDelete)
150{
151 int rc = VINF_SUCCESS;
152
153 /* Freeing a never allocated image (e.g. because the open failed) is
154 * not signalled as an error. After all nothing bad happens. */
155 if (pImage)
156 {
157 if (pImage->pStorage)
158 {
159 /* No point updating the file that is deleted anyway. */
160 if (!fDelete)
161 parallelsFlushImage(pImage);
162
163 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
164 pImage->pStorage = NULL;
165 }
166
167 if (pImage->pAllocationBitmap)
168 {
169 RTMemFree(pImage->pAllocationBitmap);
170 pImage->pAllocationBitmap = NULL;
171 }
172
173 if (fDelete && pImage->pszFilename)
174 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
175 }
176
177 return rc;
178}
179
180static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
181{
182 int rc = VINF_SUCCESS;
183 ParallelsHeader parallelsHeader;
184
185 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
186 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
187 pImage->uOpenFlags = uOpenFlags;
188 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
189
190 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
191 VDOpenFlagsToFileOpenFlags(uOpenFlags,
192 false /* fCreate */),
193 &pImage->pStorage);
194 if (RT_FAILURE(rc))
195 goto out;
196
197 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbFileCurrent);
198 if (RT_FAILURE(rc))
199 goto out;
200 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
201
202 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0,
203 &parallelsHeader, sizeof(parallelsHeader));
204 if (RT_FAILURE(rc))
205 goto out;
206
207 if (memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16))
208 {
209 /* Check if the file has hdd as extension. It is a fixed size raw image then. */
210 char *pszSuffix = RTPathSuffix(pImage->pszFilename);
211 if (strcmp(pszSuffix, ".hdd"))
212 {
213 rc = VERR_VD_PARALLELS_INVALID_HEADER;
214 goto out;
215 }
216
217 /* This is a fixed size image. */
218 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
219 pImage->cbSize = pImage->cbFileCurrent;
220
221 pImage->PCHSGeometry.cHeads = 16;
222 pImage->PCHSGeometry.cSectors = 63;
223 uint64_t cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
224 pImage->PCHSGeometry.cCylinders = (uint32_t)cCylinders;
225 }
226 else
227 {
228 if (parallelsHeader.uVersion != PARALLELS_DISK_VERSION)
229 {
230 rc = VERR_NOT_SUPPORTED;
231 goto out;
232 }
233
234 if (parallelsHeader.cEntriesInAllocationBitmap > (1 << 30))
235 {
236 rc = VERR_NOT_SUPPORTED;
237 goto out;
238 }
239
240 Log(("cSectors=%u\n", parallelsHeader.cSectors));
241 pImage->cbSize = ((uint64_t)parallelsHeader.cSectors) * 512;
242 pImage->uImageFlags = VD_IMAGE_FLAGS_NONE;
243 pImage->cAllocationBitmapEntries = parallelsHeader.cEntriesInAllocationBitmap;
244 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ((uint32_t)pImage->cAllocationBitmapEntries * sizeof(uint32_t));
245 if (!pImage->pAllocationBitmap)
246 {
247 rc = VERR_NO_MEMORY;
248 goto out;
249 }
250
251 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
252 sizeof(ParallelsHeader), pImage->pAllocationBitmap,
253 pImage->cAllocationBitmapEntries * sizeof(uint32_t));
254 if (RT_FAILURE(rc))
255 goto out;
256
257 pImage->PCHSGeometry.cCylinders = parallelsHeader.cCylinders;
258 pImage->PCHSGeometry.cHeads = parallelsHeader.cHeads;
259 pImage->PCHSGeometry.cSectors = parallelsHeader.cSectorsPerTrack;
260 }
261
262out:
263 LogFlowFunc(("returns %Rrc\n", rc));
264 return rc;
265}
266
267/**
268 * Internal: Create a parallels image.
269 */
270static int parallelsCreateImage(PPARALLELSIMAGE pImage, uint64_t cbSize,
271 unsigned uImageFlags, const char *pszComment,
272 PCVDGEOMETRY pPCHSGeometry,
273 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
274 PFNVDPROGRESS pfnProgress, void *pvUser,
275 unsigned uPercentStart, unsigned uPercentSpan)
276{
277 int rc = VINF_SUCCESS;
278 int32_t fOpen;
279
280 if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
281 {
282 rc = vdIfError(pImage->pIfError, VERR_VD_INVALID_TYPE, RT_SRC_POS, N_("Parallels: cannot create fixed image '%s'. Create a raw image"), pImage->pszFilename);
283 goto out;
284 }
285
286 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
287 pImage->uImageFlags = uImageFlags;
288 pImage->PCHSGeometry = *pPCHSGeometry;
289 pImage->LCHSGeometry = *pLCHSGeometry;
290
291 if (!pImage->PCHSGeometry.cCylinders)
292 {
293 /* Set defaults. */
294 pImage->PCHSGeometry.cSectors = 63;
295 pImage->PCHSGeometry.cHeads = 16;
296 pImage->PCHSGeometry.cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
297 }
298
299 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
300 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
301 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
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_FAILURE(rc))
307 {
308 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Parallels: cannot create image '%s'"), pImage->pszFilename);
309 goto out;
310 }
311
312 if (RT_SUCCESS(rc) && pfnProgress)
313 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
314
315 /* Setup image state. */
316 pImage->cbSize = cbSize;
317 pImage->cAllocationBitmapEntries = cbSize / 512 / pImage->PCHSGeometry.cSectors;
318 if (pImage->cAllocationBitmapEntries * pImage->PCHSGeometry.cSectors * 512 < cbSize)
319 pImage->cAllocationBitmapEntries++;
320 pImage->fAllocationBitmapChanged = true;
321 pImage->cbFileCurrent = sizeof(ParallelsHeader) + pImage->cAllocationBitmapEntries * sizeof(uint32_t);
322 /* Round to next sector boundary. */
323 pImage->cbFileCurrent += 512 - pImage->cbFileCurrent % 512;
324 Assert(!(pImage->cbFileCurrent % 512));
325 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ(pImage->cAllocationBitmapEntries * sizeof(uint32_t));
326 if (!pImage->pAllocationBitmap)
327 rc = VERR_NO_MEMORY;
328
329 if (RT_SUCCESS(rc))
330 {
331 ParallelsHeader Header;
332
333 memcpy(Header.HeaderIdentifier, PARALLELS_HEADER_MAGIC, sizeof(Header.HeaderIdentifier));
334 Header.uVersion = RT_H2LE_U32(PARALLELS_DISK_VERSION);
335 Header.cHeads = RT_H2LE_U32(pImage->PCHSGeometry.cHeads);
336 Header.cCylinders = RT_H2LE_U32(pImage->PCHSGeometry.cCylinders);
337 Header.cSectorsPerTrack = RT_H2LE_U32(pImage->PCHSGeometry.cSectors);
338 Header.cEntriesInAllocationBitmap = RT_H2LE_U32(pImage->cAllocationBitmapEntries);
339 Header.cSectors = RT_H2LE_U32(pImage->cbSize / 512);
340 memset(Header.Padding, 0, sizeof(Header.Padding));
341
342 /* Write header and allocation bitmap. */
343 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbFileCurrent);
344 if (RT_SUCCESS(rc))
345 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0,
346 &Header, sizeof(Header));
347 if (RT_SUCCESS(rc))
348 rc = parallelsFlushImage(pImage); /* Writes the allocation bitmap. */
349 }
350
351out:
352 if (RT_SUCCESS(rc) && pfnProgress)
353 pfnProgress(pvUser, uPercentStart + uPercentSpan);
354
355 if (RT_FAILURE(rc))
356 parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
357 return rc;
358}
359
360/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
361static DECLCALLBACK(int) parallelsCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
362 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
363{
364 int rc;
365 PVDIOSTORAGE pStorage;
366 ParallelsHeader parallelsHeader;
367
368 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
369 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
370
371 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
372 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
373 false /* fCreate */),
374 &pStorage);
375 if (RT_FAILURE(rc))
376 return rc;
377
378 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &parallelsHeader,
379 sizeof(ParallelsHeader));
380 if (RT_SUCCESS(rc))
381 {
382 if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
383 && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
384 rc = VINF_SUCCESS;
385 else
386 {
387 /*
388 * The image may be an fixed size image.
389 * Unfortunately fixed sized parallels images
390 * are just raw files hence no magic header to
391 * check for.
392 * The code succeeds if the file is a multiple
393 * of 512 and if the file extensions is *.hdd
394 */
395 uint64_t cbFile;
396 char *pszSuffix;
397
398 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
399 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
400 {
401 vdIfIoIntFileClose(pIfIo, pStorage);
402 return VERR_VD_PARALLELS_INVALID_HEADER;
403 }
404
405 pszSuffix = RTPathSuffix(pszFilename);
406 if (!pszSuffix || strcmp(pszSuffix, ".hdd"))
407 rc = VERR_VD_PARALLELS_INVALID_HEADER;
408 else
409 rc = VINF_SUCCESS;
410 }
411 }
412
413 if (RT_SUCCESS(rc))
414 *penmType = VDTYPE_HDD;
415
416 vdIfIoIntFileClose(pIfIo, pStorage);
417 return rc;
418}
419
420/** @copydoc VBOXHDDBACKEND::pfnOpen */
421static DECLCALLBACK(int) parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
422 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
423 VDTYPE enmType, void **ppBackendData)
424{
425 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
426 int rc;
427 PPARALLELSIMAGE pImage;
428
429 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
430
431 /* Check open flags. All valid flags are supported. */
432 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
433 {
434 rc = VERR_INVALID_PARAMETER;
435 goto out;
436 }
437
438 /* Check remaining arguments. */
439 if ( !VALID_PTR(pszFilename)
440 || !*pszFilename)
441 {
442 rc = VERR_INVALID_PARAMETER;
443 goto out;
444 }
445
446 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
447 if (!pImage)
448 {
449 rc = VERR_NO_MEMORY;
450 goto out;
451 }
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
465out:
466 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
467 return rc;
468}
469
470/** @copydoc VBOXHDDBACKEND::pfnCreate */
471static DECLCALLBACK(int) parallelsCreate(const char *pszFilename, uint64_t cbSize,
472 unsigned uImageFlags, const char *pszComment,
473 PCVDGEOMETRY pPCHSGeometry,
474 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
475 unsigned uOpenFlags, unsigned uPercentStart,
476 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
477 PVDINTERFACE pVDIfsImage,
478 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
479 void **ppBackendData)
480{
481 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",
482 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
483 int rc = VINF_SUCCESS;
484 PPARALLELSIMAGE pImage;
485
486 PFNVDPROGRESS pfnProgress = NULL;
487 void *pvUser = NULL;
488 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
489 if (pIfProgress)
490 {
491 pfnProgress = pIfProgress->pfnProgress;
492 pvUser = pIfProgress->Core.pvUser;
493 }
494
495 /* Check the VD container type. */
496 if (enmType != VDTYPE_HDD)
497 {
498 rc = VERR_VD_INVALID_TYPE;
499 goto out;
500 }
501
502 /* Check open flags. All valid flags are supported. */
503 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
504 {
505 rc = VERR_INVALID_PARAMETER;
506 goto out;
507 }
508
509 /* Check remaining arguments. */
510 if ( !VALID_PTR(pszFilename)
511 || !*pszFilename
512 || !VALID_PTR(pPCHSGeometry)
513 || !VALID_PTR(pLCHSGeometry))
514 {
515 rc = VERR_INVALID_PARAMETER;
516 goto out;
517 }
518
519 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
520 if (!pImage)
521 {
522 rc = VERR_NO_MEMORY;
523 goto out;
524 }
525 pImage->pszFilename = pszFilename;
526 pImage->pStorage = NULL;
527 pImage->pVDIfsDisk = pVDIfsDisk;
528 pImage->pVDIfsImage = pVDIfsImage;
529
530 rc = parallelsCreateImage(pImage, cbSize, uImageFlags, pszComment,
531 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
532 pfnProgress, pvUser, uPercentStart, uPercentSpan);
533 if (RT_SUCCESS(rc))
534 {
535 /* So far the image is opened in read/write mode. Make sure the
536 * image is opened in read-only mode if the caller requested that. */
537 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
538 {
539 parallelsFreeImage(pImage, false);
540 rc = parallelsOpenImage(pImage, uOpenFlags);
541 if (RT_FAILURE(rc))
542 {
543 RTMemFree(pImage);
544 goto out;
545 }
546 }
547 *ppBackendData = pImage;
548 }
549 else
550 RTMemFree(pImage);
551
552out:
553 LogFlowFunc(("returns %Rrc\n", rc));
554 return rc;
555}
556
557/** @copydoc VBOXHDDBACKEND::pfnRename */
558static DECLCALLBACK(int) parallelsRename(void *pBackendData, const char *pszFilename)
559{
560 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
561 int rc = VINF_SUCCESS;
562 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
563
564 /* Check arguments. */
565 if ( !pImage
566 || !pszFilename
567 || !*pszFilename)
568 {
569 rc = VERR_INVALID_PARAMETER;
570 goto out;
571 }
572
573 /* Close the image. */
574 rc = parallelsFreeImage(pImage, false);
575 if (RT_FAILURE(rc))
576 goto out;
577
578 /* Rename the file. */
579 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
580 if (RT_FAILURE(rc))
581 {
582 /* The move failed, try to reopen the original image. */
583 int rc2 = parallelsOpenImage(pImage, pImage->uOpenFlags);
584 if (RT_FAILURE(rc2))
585 rc = rc2;
586
587 goto out;
588 }
589
590 /* Update pImage with the new information. */
591 pImage->pszFilename = pszFilename;
592
593 /* Open the old image with new name. */
594 rc = parallelsOpenImage(pImage, pImage->uOpenFlags);
595 if (RT_FAILURE(rc))
596 goto out;
597
598out:
599 LogFlowFunc(("returns %Rrc\n", rc));
600 return rc;
601}
602
603/** @copydoc VBOXHDDBACKEND::pfnClose */
604static DECLCALLBACK(int) parallelsClose(void *pBackendData, bool fDelete)
605{
606 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
607 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
608 int rc;
609
610 rc = parallelsFreeImage(pImage, fDelete);
611 RTMemFree(pImage);
612
613 LogFlowFunc(("returns %Rrc\n", rc));
614 return rc;
615}
616
617/** @copydoc VBOXHDDBACKEND::pfnRead */
618static DECLCALLBACK(int) parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
619 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
620{
621 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
622 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
623 int rc = VINF_SUCCESS;
624 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
625 uint64_t uSector;
626 uint64_t uOffsetInFile;
627 uint32_t iIndexInAllocationTable;
628
629 AssertPtr(pImage);
630 Assert(uOffset % 512 == 0);
631 Assert(cbToRead % 512 == 0);
632
633 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
634 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
635 pIoCtx, cbToRead);
636 else
637 {
638 /* Calculate offset in the real file. */
639 uSector = uOffset / 512;
640 /* One chunk in the file is always one track big. */
641 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
642 uSector = uSector % pImage->PCHSGeometry.cSectors;
643
644 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
645
646 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
647 rc = VERR_VD_BLOCK_FREE;
648 else
649 {
650 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
651 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
652 pIoCtx, cbToRead);
653 }
654 }
655
656 *pcbActuallyRead = cbToRead;
657
658 LogFlowFunc(("returns %Rrc\n", rc));
659 return rc;
660}
661
662/** @copydoc VBOXHDDBACKEND::pfnWrite */
663static DECLCALLBACK(int) parallelsWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
664 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
665 size_t *pcbPostRead, unsigned fWrite)
666{
667 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
668 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
669 int rc = VINF_SUCCESS;
670 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
671 uint64_t uSector;
672 uint64_t uOffsetInFile;
673 uint32_t iIndexInAllocationTable;
674
675 AssertPtr(pImage);
676 Assert(uOffset % 512 == 0);
677 Assert(cbToWrite % 512 == 0);
678
679 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
680 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
681 pIoCtx, cbToWrite, NULL, NULL);
682 else
683 {
684 /* Calculate offset in the real file. */
685 uSector = uOffset / 512;
686 /* One chunk in the file is always one track big. */
687 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
688 uSector = uSector % pImage->PCHSGeometry.cSectors;
689
690 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
691
692 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
693 {
694 if (fWrite & VD_WRITE_NO_ALLOC)
695 {
696 *pcbPreRead = uSector * 512;
697 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
698
699 if (pcbWriteProcess)
700 *pcbWriteProcess = cbToWrite;
701 return VERR_VD_BLOCK_FREE;
702 }
703
704 /* Allocate new chunk in the file. */
705 Assert(uSector == 0);
706 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
707 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
708 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
709 pImage->fAllocationBitmapChanged = true;
710 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
711
712 /*
713 * Write the new block at the current end of the file.
714 */
715 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
716 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
717 if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
718 {
719 /* Write the changed allocation bitmap entry. */
720 /** @todo: Error handling. */
721 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
722 sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
723 &pImage->pAllocationBitmap[iIndexInAllocationTable],
724 sizeof(uint32_t), pIoCtx,
725 NULL, NULL);
726 }
727
728 *pcbPreRead = 0;
729 *pcbPostRead = 0;
730 }
731 else
732 {
733 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
734 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
735 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
736 }
737 }
738
739 if (pcbWriteProcess)
740 *pcbWriteProcess = cbToWrite;
741
742 LogFlowFunc(("returns %Rrc\n", rc));
743 return rc;
744}
745
746/** @copydoc VBOXHDDBACKEND::pfnFlush */
747static DECLCALLBACK(int) parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
748{
749 int rc = VINF_SUCCESS;
750 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
751
752 LogFlowFunc(("pImage=#%p\n", pImage));
753
754 /* Flush the file, everything is up to date already. */
755 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
756
757 LogFlowFunc(("returns %Rrc\n", rc));
758 return rc;
759}
760
761/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
762static DECLCALLBACK(unsigned) parallelsGetVersion(void *pBackendData)
763{
764 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
765 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
766
767 AssertPtr(pImage);
768
769 if (pImage)
770 return PARALLELS_DISK_VERSION;
771 else
772 return 0;
773}
774
775/** @copydoc VBOXHDDBACKEND::pfnGetSectorSize */
776static DECLCALLBACK(uint32_t) parallelsGetSectorSize(void *pBackendData)
777{
778 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
779 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
780 uint32_t cb = 0;
781
782 AssertPtr(pImage);
783
784 if (pImage && pImage->pStorage)
785 cb = 512;
786
787 LogFlowFunc(("returns %llu\n", cb));
788 return cb;
789}
790
791/** @copydoc VBOXHDDBACKEND::pfnGetSize */
792static DECLCALLBACK(uint64_t) parallelsGetSize(void *pBackendData)
793{
794 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
795 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
796 uint64_t cb = 0;
797
798 AssertPtr(pImage);
799
800 if (pImage && pImage->pStorage)
801 cb = pImage->cbSize;
802
803 LogFlowFunc(("returns %llu\n", cb));
804 return cb;
805}
806
807/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
808static DECLCALLBACK(uint64_t) parallelsGetFileSize(void *pBackendData)
809{
810 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
811 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
812 uint64_t cb = 0;
813
814 AssertPtr(pImage);
815
816 if (pImage && pImage->pStorage)
817 cb = pImage->cbFileCurrent;
818
819 LogFlowFunc(("returns %lld\n", cb));
820 return cb;
821}
822
823/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
824static DECLCALLBACK(int) parallelsGetPCHSGeometry(void *pBackendData,
825 PVDGEOMETRY pPCHSGeometry)
826{
827 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
828 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
829 int rc;
830
831 AssertPtr(pImage);
832
833 if (pImage)
834 {
835 if (pImage->PCHSGeometry.cCylinders)
836 {
837 *pPCHSGeometry = pImage->PCHSGeometry;
838 rc = VINF_SUCCESS;
839 }
840 else
841 rc = VERR_VD_GEOMETRY_NOT_SET;
842 }
843 else
844 rc = VERR_VD_NOT_OPENED;
845
846 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
847 return rc;
848}
849
850/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
851static DECLCALLBACK(int) parallelsSetPCHSGeometry(void *pBackendData,
852 PCVDGEOMETRY pPCHSGeometry)
853{
854 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
855 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
856 int rc;
857
858 AssertPtr(pImage);
859
860 if (pImage)
861 {
862 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
863 {
864 rc = VERR_VD_IMAGE_READ_ONLY;
865 goto out;
866 }
867
868 pImage->PCHSGeometry = *pPCHSGeometry;
869 rc = VINF_SUCCESS;
870 }
871 else
872 rc = VERR_VD_NOT_OPENED;
873
874out:
875 LogFlowFunc(("returns %Rrc\n", rc));
876 return rc;
877}
878
879/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
880static DECLCALLBACK(int) parallelsGetLCHSGeometry(void *pBackendData,
881 PVDGEOMETRY pLCHSGeometry)
882{
883 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
884 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
885 int rc;
886
887 AssertPtr(pImage);
888
889 if (pImage)
890 {
891 if (pImage->LCHSGeometry.cCylinders)
892 {
893 *pLCHSGeometry = pImage->LCHSGeometry;
894 rc = VINF_SUCCESS;
895 }
896 else
897 rc = VERR_VD_GEOMETRY_NOT_SET;
898 }
899 else
900 rc = VERR_VD_NOT_OPENED;
901
902 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
903 return rc;
904}
905
906/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
907static DECLCALLBACK(int) parallelsSetLCHSGeometry(void *pBackendData,
908 PCVDGEOMETRY pLCHSGeometry)
909{
910 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
911 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
912 int rc;
913
914 AssertPtr(pImage);
915
916 if (pImage)
917 {
918 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
919 {
920 rc = VERR_VD_IMAGE_READ_ONLY;
921 goto out;
922 }
923
924 pImage->LCHSGeometry = *pLCHSGeometry;
925 rc = VINF_SUCCESS;
926 }
927 else
928 rc = VERR_VD_NOT_OPENED;
929
930out:
931 LogFlowFunc(("returns %Rrc\n", rc));
932 return rc;
933}
934
935/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
936static DECLCALLBACK(unsigned) parallelsGetImageFlags(void *pBackendData)
937{
938 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
939 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
940 unsigned uImageFlags;
941
942 AssertPtr(pImage);
943
944 if (pImage)
945 uImageFlags = pImage->uImageFlags;
946 else
947 uImageFlags = 0;
948
949 LogFlowFunc(("returns %#x\n", uImageFlags));
950 return uImageFlags;
951}
952
953/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
954static DECLCALLBACK(unsigned) parallelsGetOpenFlags(void *pBackendData)
955{
956 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
957 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
958 unsigned uOpenFlags;
959
960 AssertPtr(pImage);
961
962 if (pImage)
963 uOpenFlags = pImage->uOpenFlags;
964 else
965 uOpenFlags = 0;
966
967 LogFlowFunc(("returns %#x\n", uOpenFlags));
968 return uOpenFlags;
969}
970
971/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
972static DECLCALLBACK(int) parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
973{
974 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
975 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
976 int rc;
977
978 /* Image must be opened and the new flags must be valid. */
979 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
980 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
981 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
982 {
983 rc = VERR_INVALID_PARAMETER;
984 goto out;
985 }
986
987 /* Implement this operation via reopening the image. */
988 parallelsFreeImage(pImage, false);
989 rc = parallelsOpenImage(pImage, uOpenFlags);
990
991out:
992 LogFlowFunc(("returns %Rrc\n", rc));
993 return rc;
994}
995
996/** @copydoc VBOXHDDBACKEND::pfnGetComment */
997static DECLCALLBACK(int) parallelsGetComment(void *pBackendData, char *pszComment,
998 size_t cbComment)
999{
1000 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
1001 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1002 int rc;
1003
1004 AssertPtr(pImage);
1005
1006 if (pImage)
1007 rc = VERR_NOT_SUPPORTED;
1008 else
1009 rc = VERR_VD_NOT_OPENED;
1010
1011 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
1012 return rc;
1013}
1014
1015/** @copydoc VBOXHDDBACKEND::pfnSetComment */
1016static DECLCALLBACK(int) parallelsSetComment(void *pBackendData, const char *pszComment)
1017{
1018 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
1019 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1020 int rc;
1021
1022 AssertPtr(pImage);
1023
1024 if (pImage)
1025 {
1026 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1027 rc = VERR_VD_IMAGE_READ_ONLY;
1028 else
1029 rc = VERR_NOT_SUPPORTED;
1030 }
1031 else
1032 rc = VERR_VD_NOT_OPENED;
1033
1034 LogFlowFunc(("returns %Rrc\n", rc));
1035 return rc;
1036}
1037
1038/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
1039static DECLCALLBACK(int) parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
1040{
1041 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1042 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1043 int rc;
1044
1045 AssertPtr(pImage);
1046
1047 if (pImage)
1048 rc = VERR_NOT_SUPPORTED;
1049 else
1050 rc = VERR_VD_NOT_OPENED;
1051
1052 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1053 return rc;
1054}
1055
1056/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
1057static DECLCALLBACK(int) parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
1058{
1059 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1060 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1061 int rc;
1062
1063 AssertPtr(pImage);
1064
1065 if (pImage)
1066 {
1067 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1068 rc = VERR_NOT_SUPPORTED;
1069 else
1070 rc = VERR_VD_IMAGE_READ_ONLY;
1071 }
1072 else
1073 rc = VERR_VD_NOT_OPENED;
1074
1075 LogFlowFunc(("returns %Rrc\n", rc));
1076 return rc;
1077}
1078
1079/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1080static DECLCALLBACK(int) parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1081{
1082 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1083 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1084 int rc;
1085
1086 AssertPtr(pImage);
1087
1088 if (pImage)
1089 rc = VERR_NOT_SUPPORTED;
1090 else
1091 rc = VERR_VD_NOT_OPENED;
1092
1093 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1094 return rc;
1095}
1096
1097/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1098static DECLCALLBACK(int) parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1099{
1100 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1101 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1102 int rc;
1103
1104 AssertPtr(pImage);
1105
1106 if (pImage)
1107 {
1108 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1109 rc = VERR_NOT_SUPPORTED;
1110 else
1111 rc = VERR_VD_IMAGE_READ_ONLY;
1112 }
1113 else
1114 rc = VERR_VD_NOT_OPENED;
1115
1116 LogFlowFunc(("returns %Rrc\n", rc));
1117 return rc;
1118}
1119
1120/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1121static DECLCALLBACK(int) parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
1122{
1123 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1124 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1125 int rc;
1126
1127 AssertPtr(pImage);
1128
1129 if (pImage)
1130 rc = VERR_NOT_SUPPORTED;
1131 else
1132 rc = VERR_VD_NOT_OPENED;
1133
1134 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1135 return rc;
1136}
1137
1138/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1139static DECLCALLBACK(int) parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1140{
1141 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1142 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1143 int rc;
1144
1145 AssertPtr(pImage);
1146
1147 if (pImage)
1148 {
1149 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1150 rc = VERR_NOT_SUPPORTED;
1151 else
1152 rc = VERR_VD_IMAGE_READ_ONLY;
1153 }
1154 else
1155 rc = VERR_VD_NOT_OPENED;
1156
1157 LogFlowFunc(("returns %Rrc\n", rc));
1158 return rc;
1159}
1160
1161/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1162static DECLCALLBACK(int) parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1163{
1164 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1165 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1166 int rc;
1167
1168 AssertPtr(pImage);
1169
1170 if (pImage)
1171 rc = VERR_NOT_SUPPORTED;
1172 else
1173 rc = VERR_VD_NOT_OPENED;
1174
1175 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1176 return rc;
1177}
1178
1179/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1180static DECLCALLBACK(int) parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1181{
1182 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1183 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1184 int rc;
1185
1186 AssertPtr(pImage);
1187
1188 if (pImage)
1189 {
1190 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1191 rc = VERR_NOT_SUPPORTED;
1192 else
1193 rc = VERR_VD_IMAGE_READ_ONLY;
1194 }
1195 else
1196 rc = VERR_VD_NOT_OPENED;
1197
1198 LogFlowFunc(("returns %Rrc\n", rc));
1199 return rc;
1200}
1201
1202/** @copydoc VBOXHDDBACKEND::pfnDump */
1203static DECLCALLBACK(void) parallelsDump(void *pBackendData)
1204{
1205 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1206
1207 AssertPtr(pImage);
1208 if (pImage)
1209 {
1210 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
1211 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1212 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
1213 }
1214}
1215
1216
1217
1218const VBOXHDDBACKEND g_ParallelsBackend =
1219{
1220 /* pszBackendName */
1221 "Parallels",
1222 /* cbSize */
1223 sizeof(VBOXHDDBACKEND),
1224 /* uBackendCaps */
1225 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
1226 /* paFileExtensions */
1227 s_aParallelsFileExtensions,
1228 /* paConfigInfo */
1229 NULL,
1230 /* pfnCheckIfValid */
1231 parallelsCheckIfValid,
1232 /* pfnOpen */
1233 parallelsOpen,
1234 /* pfnCreate */
1235 parallelsCreate,
1236 /* pfnRename */
1237 parallelsRename,
1238 /* pfnClose */
1239 parallelsClose,
1240 /* pfnRead */
1241 parallelsRead,
1242 /* pfnWrite */
1243 parallelsWrite,
1244 /* pfnFlush */
1245 parallelsFlush,
1246 /* pfnDiscard */
1247 NULL,
1248 /* pfnGetVersion */
1249 parallelsGetVersion,
1250 /* pfnGetSectorSize */
1251 parallelsGetSectorSize,
1252 /* pfnGetSize */
1253 parallelsGetSize,
1254 /* pfnGetFileSize */
1255 parallelsGetFileSize,
1256 /* pfnGetPCHSGeometry */
1257 parallelsGetPCHSGeometry,
1258 /* pfnSetPCHSGeometry */
1259 parallelsSetPCHSGeometry,
1260 /* pfnGetLCHSGeometry */
1261 parallelsGetLCHSGeometry,
1262 /* pfnSetLCHSGeometry */
1263 parallelsSetLCHSGeometry,
1264 /* pfnGetImageFlags */
1265 parallelsGetImageFlags,
1266 /* pfnGetOpenFlags */
1267 parallelsGetOpenFlags,
1268 /* pfnSetOpenFlags */
1269 parallelsSetOpenFlags,
1270 /* pfnGetComment */
1271 parallelsGetComment,
1272 /* pfnSetComment */
1273 parallelsSetComment,
1274 /* pfnGetUuid */
1275 parallelsGetUuid,
1276 /* pfnSetUuid */
1277 parallelsSetUuid,
1278 /* pfnGetModificationUuid */
1279 parallelsGetModificationUuid,
1280 /* pfnSetModificationUuid */
1281 parallelsSetModificationUuid,
1282 /* pfnGetParentUuid */
1283 parallelsGetParentUuid,
1284 /* pfnSetParentUuid */
1285 parallelsSetParentUuid,
1286 /* pfnGetParentModificationUuid */
1287 parallelsGetParentModificationUuid,
1288 /* pfnSetParentModificationUuid */
1289 parallelsSetParentModificationUuid,
1290 /* pfnDump */
1291 parallelsDump,
1292 /* pfnGetTimestamp */
1293 NULL,
1294 /* pfnGetParentTimestamp */
1295 NULL,
1296 /* pfnSetParentTimestamp */
1297 NULL,
1298 /* pfnGetParentFilename */
1299 NULL,
1300 /* pfnSetParentFilename */
1301 NULL,
1302 /* pfnComposeLocation */
1303 genericFileComposeLocation,
1304 /* pfnComposeName */
1305 genericFileComposeName,
1306 /* pfnCompact */
1307 NULL,
1308 /* pfnResize */
1309 NULL,
1310 /* pfnRepair */
1311 NULL,
1312 /* pfnTraverseMetadata */
1313 NULL
1314};
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