VirtualBox

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

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

scm: cleaning up todos

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