VirtualBox

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

Last change on this file since 56319 was 54430, checked in by vboxsync, 10 years ago

Storage/VD: make use of the image type (hdd/dvd/floppy) for sanity checking when creating disk images

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