VirtualBox

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

Last change on this file since 35813 was 35486, checked in by vboxsync, 14 years ago

Storage/Parallels: Fix regression introduced with r65918. Don't delete the parallels image when changing the open flags

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.2 KB
Line 
1/* $Id: Parallels.cpp 35486 2011-01-11 13:44:31Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2010 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
30#define PARALLELS_HEADER_MAGIC "WithoutFreeSpace"
31#define PARALLELS_DISK_VERSION 2
32
33/** The header of the parallels disk. */
34#pragma pack(1)
35typedef struct ParallelsHeader
36{
37 /** The magic header to identify a parallels hdd image. */
38 char HeaderIdentifier[16];
39 /** The version of the disk image. */
40 uint32_t uVersion;
41 /** The number of heads the hdd has. */
42 uint32_t cHeads;
43 /** Number of cylinders. */
44 uint32_t cCylinders;
45 /** Number of sectors per track. */
46 uint32_t cSectorsPerTrack;
47 /** Number of entries in the allocation bitmap. */
48 uint32_t cEntriesInAllocationBitmap;
49 /** Total number of sectors. */
50 uint32_t cSectors;
51 /** Padding. */
52 char Padding[24];
53} ParallelsHeader;
54#pragma pack()
55
56/**
57 * Parallels image structure.
58 */
59typedef struct PARALLELSIMAGE
60{
61 /** Image file name. */
62 const char *pszFilename;
63 /** Opaque storage handle. */
64 PVDIOSTORAGE pStorage;
65
66 /** I/O interface. */
67 PVDINTERFACE pInterfaceIO;
68 /** I/O interface callbacks. */
69 PVDINTERFACEIOINT pInterfaceIOCallbacks;
70
71 /** Pointer to the per-disk VD interface list. */
72 PVDINTERFACE pVDIfsDisk;
73 /** Pointer to the per-image VD interface list. */
74 PVDINTERFACE pVDIfsImage;
75 /** Error interface. */
76 PVDINTERFACE pInterfaceError;
77 /** Error interface callbacks. */
78 PVDINTERFACEERROR pInterfaceErrorCallbacks;
79
80 /** Open flags passed by VBoxHDD layer. */
81 unsigned uOpenFlags;
82 /** Image flags defined during creation or determined during open. */
83 unsigned uImageFlags;
84 /** Total size of the image. */
85 uint64_t cbSize;
86
87 /** Physical geometry of this image. */
88 VDGEOMETRY PCHSGeometry;
89 /** Logical geometry of this image. */
90 VDGEOMETRY LCHSGeometry;
91
92 /** Pointer to the allocation bitmap. */
93 uint32_t *pAllocationBitmap;
94 /** Entries in the allocation bitmap. */
95 uint64_t cAllocationBitmapEntries;
96 /** Flag whether the allocation bitmap was changed. */
97 bool fAllocationBitmapChanged;
98 /** Current file size. */
99 uint64_t cbFileCurrent;
100} PARALLELSIMAGE, *PPARALLELSIMAGE;
101
102/*******************************************************************************
103* Static Variables *
104*******************************************************************************/
105
106/** NULL-terminated array of supported file extensions. */
107static const VDFILEEXTENSION s_aParallelsFileExtensions[] =
108{
109 {"hdd", VDTYPE_HDD},
110 {NULL, VDTYPE_INVALID}
111};
112
113/***************************************************
114 * Internal functions *
115 **************************************************/
116
117/**
118 * Internal: signal an error to the frontend.
119 */
120DECLINLINE(int) parallelsError(PPARALLELSIMAGE pImage, int rc, RT_SRC_POS_DECL,
121 const char *pszFormat, ...)
122{
123 va_list va;
124 va_start(va, pszFormat);
125 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
126 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
127 pszFormat, va);
128 va_end(va);
129 return rc;
130}
131
132/**
133 * Internal: signal an informational message to the frontend.
134 */
135DECLINLINE(int) parallelsMessage(PPARALLELSIMAGE pImage, const char *pszFormat, ...)
136{
137 int rc = VINF_SUCCESS;
138 va_list va;
139 va_start(va, pszFormat);
140 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
141 rc = pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser,
142 pszFormat, va);
143 va_end(va);
144 return rc;
145}
146
147
148DECLINLINE(int) parallelsFileOpen(PPARALLELSIMAGE pImage, const char *pszFilename,
149 uint32_t fOpen)
150{
151 return pImage->pInterfaceIOCallbacks->pfnOpen(pImage->pInterfaceIO->pvUser,
152 pszFilename, fOpen,
153 &pImage->pStorage);
154}
155
156DECLINLINE(int) parallelsFileClose(PPARALLELSIMAGE pImage)
157{
158 return pImage->pInterfaceIOCallbacks->pfnClose(pImage->pInterfaceIO->pvUser,
159 pImage->pStorage);
160}
161
162DECLINLINE(int) parallelsFileDelete(PPARALLELSIMAGE pImage, const char *pszFilename)
163{
164 return pImage->pInterfaceIOCallbacks->pfnDelete(pImage->pInterfaceIO->pvUser,
165 pszFilename);
166}
167
168DECLINLINE(int) parallelsFileMove(PPARALLELSIMAGE pImage, const char *pszSrc,
169 const char *pszDst, unsigned fMove)
170{
171 return pImage->pInterfaceIOCallbacks->pfnMove(pImage->pInterfaceIO->pvUser,
172 pszSrc, pszDst, fMove);
173}
174
175DECLINLINE(int) parallelsFileGetSize(PPARALLELSIMAGE pImage, uint64_t *pcbSize)
176{
177 return pImage->pInterfaceIOCallbacks->pfnGetSize(pImage->pInterfaceIO->pvUser,
178 pImage->pStorage, pcbSize);
179}
180
181DECLINLINE(int) parallelsFileSetSize(PPARALLELSIMAGE pImage, uint64_t cbSize)
182{
183 return pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
184 pImage->pStorage, cbSize);
185}
186
187DECLINLINE(int) parallelsFileWriteSync(PPARALLELSIMAGE pImage, uint64_t uOffset,
188 const void *pvBuffer, size_t cbBuffer,
189 size_t *pcbWritten)
190{
191 return pImage->pInterfaceIOCallbacks->pfnWriteSync(pImage->pInterfaceIO->pvUser,
192 pImage->pStorage, uOffset,
193 pvBuffer, cbBuffer, pcbWritten);
194}
195
196DECLINLINE(int) parallelsFileReadSync(PPARALLELSIMAGE pImage, uint64_t uOffset,
197 void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
198{
199 return pImage->pInterfaceIOCallbacks->pfnReadSync(pImage->pInterfaceIO->pvUser,
200 pImage->pStorage, uOffset,
201 pvBuffer, cbBuffer, pcbRead);
202}
203
204DECLINLINE(int) parallelsFileFlushSync(PPARALLELSIMAGE pImage)
205{
206 return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
207 pImage->pStorage);
208}
209
210DECLINLINE(int) parallelsFileReadUserAsync(PPARALLELSIMAGE pImage, uint64_t uOffset,
211 PVDIOCTX pIoCtx, size_t cbRead)
212{
213 return pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
214 pImage->pStorage,
215 uOffset, pIoCtx,
216 cbRead);
217}
218
219DECLINLINE(int) parallelsFileWriteUserAsync(PPARALLELSIMAGE pImage, uint64_t uOffset,
220 PVDIOCTX pIoCtx, size_t cbWrite,
221 PFNVDXFERCOMPLETED pfnComplete,
222 void *pvCompleteUser)
223{
224 return pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
225 pImage->pStorage,
226 uOffset, pIoCtx,
227 cbWrite,
228 pfnComplete,
229 pvCompleteUser);
230}
231
232DECLINLINE(int) parallelsFileWriteMetaAsync(PPARALLELSIMAGE pImage, uint64_t uOffset,
233 void *pvBuffer, size_t cbBuffer,
234 PVDIOCTX pIoCtx,
235 PFNVDXFERCOMPLETED pfnComplete,
236 void *pvCompleteUser)
237{
238 return pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
239 pImage->pStorage,
240 uOffset, pvBuffer,
241 cbBuffer, pIoCtx,
242 pfnComplete,
243 pvCompleteUser);
244}
245
246DECLINLINE(int) parallelsFileFlushAsync(PPARALLELSIMAGE pImage, PVDIOCTX pIoCtx,
247 PFNVDXFERCOMPLETED pfnComplete,
248 void *pvCompleteUser)
249{
250 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
251 pImage->pStorage,
252 pIoCtx, pfnComplete,
253 pvCompleteUser);
254}
255
256
257/**
258 * Internal. Flush image data to disk.
259 */
260static int parallelsFlushImage(PPARALLELSIMAGE pImage)
261{
262 int rc = VINF_SUCCESS;
263
264 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
265 return VINF_SUCCESS;
266
267 if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
268 && (pImage->fAllocationBitmapChanged))
269 {
270 pImage->fAllocationBitmapChanged = false;
271 /* Write the allocation bitmap to the file. */
272 rc = parallelsFileWriteSync(pImage, sizeof(ParallelsHeader),
273 pImage->pAllocationBitmap,
274 pImage->cAllocationBitmapEntries * sizeof(uint32_t),
275 NULL);
276 if (RT_FAILURE(rc))
277 return rc;
278 }
279
280 /* Flush file. */
281 rc = parallelsFileFlushSync(pImage);
282
283 LogFlowFunc(("returns %Rrc\n", rc));
284 return rc;
285}
286
287/**
288 * Internal. Free all allocated space for representing an image except pImage,
289 * and optionally delete the image from disk.
290 */
291static int parallelsFreeImage(PPARALLELSIMAGE pImage, bool fDelete)
292{
293 int rc = VINF_SUCCESS;
294
295 /* Freeing a never allocated image (e.g. because the open failed) is
296 * not signalled as an error. After all nothing bad happens. */
297 if (pImage)
298 {
299 if (pImage->pStorage)
300 {
301 /* No point updating the file that is deleted anyway. */
302 if (!fDelete)
303 parallelsFlushImage(pImage);
304
305 parallelsFileClose(pImage);
306 pImage->pStorage = NULL;
307 }
308
309 if (pImage->pAllocationBitmap)
310 {
311 RTMemFree(pImage->pAllocationBitmap);
312 pImage->pAllocationBitmap = NULL;
313 }
314
315 if (fDelete && pImage->pszFilename)
316 parallelsFileDelete(pImage, pImage->pszFilename);
317 }
318
319 return rc;
320}
321
322static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
323{
324 int rc = VINF_SUCCESS;
325 ParallelsHeader parallelsHeader;
326
327 /* Try to get error interface. */
328 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
329 if (pImage->pInterfaceError)
330 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
331
332 /* Get I/O interface. */
333 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
334 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
335 pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
336 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
337
338 rc = parallelsFileOpen(pImage, pImage->pszFilename,
339 VDOpenFlagsToFileOpenFlags(uOpenFlags,
340 false /* fCreate */));
341 if (RT_FAILURE(rc))
342 goto out;
343
344 rc = parallelsFileGetSize(pImage, &pImage->cbFileCurrent);
345 if (RT_FAILURE(rc))
346 goto out;
347 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
348
349 rc = parallelsFileReadSync(pImage, 0, &parallelsHeader, sizeof(parallelsHeader), NULL);
350 if (RT_FAILURE(rc))
351 goto out;
352
353 if (memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16))
354 {
355 /* Check if the file has hdd as extension. It is a fixed size raw image then. */
356 char *pszExtension = RTPathExt(pImage->pszFilename);
357 if (strcmp(pszExtension, ".hdd"))
358 {
359 rc = VERR_VD_PARALLELS_INVALID_HEADER;
360 goto out;
361 }
362
363 /* This is a fixed size image. */
364 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
365 pImage->cbSize = pImage->cbFileCurrent;
366
367 pImage->PCHSGeometry.cHeads = 16;
368 pImage->PCHSGeometry.cSectors = 63;
369 uint64_t cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
370 pImage->PCHSGeometry.cCylinders = (uint32_t)cCylinders;
371 }
372 else
373 {
374 if (parallelsHeader.uVersion != PARALLELS_DISK_VERSION)
375 {
376 rc = VERR_NOT_SUPPORTED;
377 goto out;
378 }
379
380 if (parallelsHeader.cEntriesInAllocationBitmap > (1 << 30))
381 {
382 rc = VERR_NOT_SUPPORTED;
383 goto out;
384 }
385
386 Log(("cSectors=%u\n", parallelsHeader.cSectors));
387 pImage->cbSize = ((uint64_t)parallelsHeader.cSectors) * 512;
388 pImage->uImageFlags = VD_IMAGE_FLAGS_NONE;
389 pImage->cAllocationBitmapEntries = parallelsHeader.cEntriesInAllocationBitmap;
390 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ((uint32_t)pImage->cAllocationBitmapEntries * sizeof(uint32_t));
391 if (!pImage->pAllocationBitmap)
392 {
393 rc = VERR_NO_MEMORY;
394 goto out;
395 }
396
397 rc = parallelsFileReadSync(pImage, sizeof(ParallelsHeader),
398 pImage->pAllocationBitmap,
399 pImage->cAllocationBitmapEntries * sizeof(uint32_t),
400 NULL);
401 if (RT_FAILURE(rc))
402 goto out;
403
404 pImage->PCHSGeometry.cCylinders = parallelsHeader.cCylinders;
405 pImage->PCHSGeometry.cHeads = parallelsHeader.cHeads;
406 pImage->PCHSGeometry.cSectors = parallelsHeader.cSectorsPerTrack;
407 }
408
409out:
410 LogFlowFunc(("returns %Rrc\n", rc));
411 return rc;
412}
413
414
415/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
416static int parallelsCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
417 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
418{
419 int rc;
420 PVDIOSTORAGE pStorage;
421 ParallelsHeader parallelsHeader;
422
423 /* Get I/O interface. */
424 PVDINTERFACE pInterfaceIO = VDInterfaceGet(pVDIfsImage, VDINTERFACETYPE_IOINT);
425 AssertPtrReturn(pInterfaceIO, VERR_INVALID_PARAMETER);
426 PVDINTERFACEIOINT pInterfaceIOCallbacks = VDGetInterfaceIOInt(pInterfaceIO);
427 AssertPtrReturn(pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
428
429 rc = pInterfaceIOCallbacks->pfnOpen(pInterfaceIO->pvUser, pszFilename,
430 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
431 false /* fCreate */),
432 &pStorage);
433 if (RT_FAILURE(rc))
434 return rc;
435
436 rc = pInterfaceIOCallbacks->pfnReadSync(pInterfaceIO->pvUser, pStorage,
437 0, &parallelsHeader,
438 sizeof(ParallelsHeader), NULL);
439 if (RT_SUCCESS(rc))
440 {
441 if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
442 && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
443 rc = VINF_SUCCESS;
444 else
445 {
446 /*
447 * The image may be an fixed size image.
448 * Unfortunately fixed sized parallels images
449 * are just raw files hence no magic header to
450 * check for.
451 * The code succeeds if the file is a multiple
452 * of 512 and if the file extensions is *.hdd
453 */
454 uint64_t cbFile;
455 char *pszExtension;
456
457 rc = pInterfaceIOCallbacks->pfnGetSize(pInterfaceIO->pvUser, pStorage,
458 &cbFile);
459 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
460 {
461 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
462 return VERR_VD_PARALLELS_INVALID_HEADER;
463 }
464
465 pszExtension = RTPathExt(pszFilename);
466 if (!pszExtension || strcmp(pszExtension, ".hdd"))
467 rc = VERR_VD_PARALLELS_INVALID_HEADER;
468 else
469 rc = VINF_SUCCESS;
470 }
471 }
472
473 if (RT_SUCCESS(rc))
474 *penmType = VDTYPE_HDD;
475
476 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
477 return rc;
478}
479
480/** @copydoc VBOXHDDBACKEND::pfnOpen */
481static int parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
482 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
483 VDTYPE enmType, void **ppBackendData)
484{
485 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
486 int rc;
487 PPARALLELSIMAGE pImage;
488
489 /* Check open flags. All valid flags are supported. */
490 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
491 {
492 rc = VERR_INVALID_PARAMETER;
493 goto out;
494 }
495
496 /* Check remaining arguments. */
497 if ( !VALID_PTR(pszFilename)
498 || !*pszFilename)
499 {
500 rc = VERR_INVALID_PARAMETER;
501 goto out;
502 }
503
504 /** @todo r=klaus why this duplicate check, async is not claimed... */
505 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
506 {
507 rc = VERR_NOT_SUPPORTED;
508 goto out;
509 }
510
511 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
512 if (!pImage)
513 {
514 rc = VERR_NO_MEMORY;
515 goto out;
516 }
517
518 pImage->pszFilename = pszFilename;
519 pImage->pStorage = NULL;
520 pImage->pVDIfsDisk = pVDIfsDisk;
521 pImage->pVDIfsImage = pVDIfsImage;
522 pImage->fAllocationBitmapChanged = false;
523
524 rc = parallelsOpenImage(pImage, uOpenFlags);
525 if (RT_SUCCESS(rc))
526 *ppBackendData = pImage;
527 else
528 RTMemFree(pImage);
529
530out:
531 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
532 return rc;
533}
534
535/** @copydoc VBOXHDDBACKEND::pfnCreate */
536static int parallelsCreate(const char *pszFilename, uint64_t cbSize,
537 unsigned uImageFlags, const char *pszComment,
538 PCVDGEOMETRY pPCHSGeometry,
539 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
540 unsigned uOpenFlags, unsigned uPercentStart,
541 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
542 PVDINTERFACE pVDIfsImage,
543 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
544{
545 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 ppBackendData=%#p", pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
546 int rc = VERR_NOT_IMPLEMENTED;
547
548 LogFlowFunc(("returns %Rrc\n", rc));
549 return rc;
550}
551
552/** @copydoc VBOXHDDBACKEND::pfnRename */
553static int parallelsRename(void *pBackendData, const char *pszFilename)
554{
555 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
556 int rc = VINF_SUCCESS;
557 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
558
559 /* Check arguments. */
560 if ( !pImage
561 || !pszFilename
562 || !*pszFilename)
563 {
564 rc = VERR_INVALID_PARAMETER;
565 goto out;
566 }
567
568 /* Close the image. */
569 rc = parallelsFreeImage(pImage, false);
570 if (RT_FAILURE(rc))
571 goto out;
572
573 /* Rename the file. */
574 rc = parallelsFileMove(pImage, pImage->pszFilename, pszFilename, 0);
575 if (RT_FAILURE(rc))
576 {
577 /* The move failed, try to reopen the original image. */
578 int rc2 = parallelsOpenImage(pImage, pImage->uOpenFlags);
579 if (RT_FAILURE(rc2))
580 rc = rc2;
581
582 goto out;
583 }
584
585 /* Update pImage with the new information. */
586 pImage->pszFilename = pszFilename;
587
588 /* Open the old image with new name. */
589 rc = parallelsOpenImage(pImage, pImage->uOpenFlags);
590 if (RT_FAILURE(rc))
591 goto out;
592
593out:
594 LogFlowFunc(("returns %Rrc\n", rc));
595 return rc;
596}
597
598/** @copydoc VBOXHDDBACKEND::pfnClose */
599static int parallelsClose(void *pBackendData, bool fDelete)
600{
601 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
602 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
603 int rc;
604
605 rc = parallelsFreeImage(pImage, fDelete);
606 RTMemFree(pImage);
607
608 LogFlowFunc(("returns %Rrc\n", rc));
609 return rc;
610}
611
612/** @copydoc VBOXHDDBACKEND::pfnRead */
613static int parallelsRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
614 size_t cbBuf, size_t *pcbActuallyRead)
615{
616 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbBuf=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbActuallyRead));
617 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
618 int rc = VINF_SUCCESS;
619 uint64_t uSector;
620 uint64_t uOffsetInFile;
621 uint32_t iIndexInAllocationTable;
622
623 AssertPtr(pImage);
624 Assert(uOffset % 512 == 0);
625 Assert(cbBuf % 512 == 0);
626
627 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
628 {
629 rc = parallelsFileReadSync(pImage, uOffset, pvBuf, cbBuf, NULL);
630 }
631 else
632 {
633 /* Calculate offset in the real file. */
634 uSector = uOffset / 512;
635 /* One chunk in the file is always one track big. */
636 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
637 uSector = uSector % pImage->PCHSGeometry.cSectors;
638
639 cbBuf = RT_MIN(cbBuf, (pImage->PCHSGeometry.cSectors - uSector)*512);
640
641 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
642 {
643 rc = VERR_VD_BLOCK_FREE;
644 }
645 else
646 {
647 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
648 rc = parallelsFileReadSync(pImage, uOffsetInFile, pvBuf, cbBuf, NULL);
649 }
650 }
651
652 if (RT_SUCCESS(rc))
653 {
654 if (pcbActuallyRead)
655 *pcbActuallyRead = cbBuf;
656
657 Log2(("parallelsRead: off=%#llx pvBuf=%p cbBuf=%d\n"
658 "%.*Rhxd\n",
659 uOffset, pvBuf, cbBuf, cbBuf, pvBuf));
660 }
661
662 LogFlowFunc(("returns %Rrc\n", rc));
663 return rc;
664}
665
666/** @copydoc VBOXHDDBACKEND::pfnWrite */
667static int parallelsWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
668 size_t cbBuf, size_t *pcbWriteProcess,
669 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
670{
671 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbBuf=%zu pcbWriteProcess=%#p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbWriteProcess));
672 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
673 int rc = VINF_SUCCESS;
674 uint64_t uSector;
675 uint64_t uOffsetInFile;
676 uint32_t iIndexInAllocationTable;
677
678 AssertPtr(pImage);
679 Assert(uOffset % 512 == 0);
680 Assert(cbBuf % 512 == 0);
681
682 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
683 {
684 rc = parallelsFileWriteSync(pImage, uOffset, pvBuf, cbBuf, NULL);
685 }
686 else
687 {
688 /** Calculate offset in the real file. */
689 uSector = uOffset / 512;
690 /** One chunk in the file is always one track big. */
691 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
692 uSector = uSector % pImage->PCHSGeometry.cSectors;
693
694 cbBuf = RT_MIN(cbBuf, (pImage->PCHSGeometry.cSectors - uSector)*512);
695
696 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
697 {
698 /* Allocate new chunk in the file. */
699 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
700 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
701 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
702 pImage->fAllocationBitmapChanged = true;
703
704 uint8_t *pNewBlock = (uint8_t *)RTMemAllocZ(pImage->PCHSGeometry.cSectors * 512);
705
706 if (!pNewBlock)
707 {
708 rc = VERR_NO_MEMORY;
709 goto out;
710 }
711
712 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
713 memcpy(pNewBlock + (uOffset - ((uint64_t)iIndexInAllocationTable * pImage->PCHSGeometry.cSectors * 512)),
714 pvBuf, cbBuf);
715
716 /*
717 * Write the new block at the current end of the file.
718 */
719 rc = parallelsFileWriteSync(pImage, uOffsetInFile, pNewBlock,
720 pImage->PCHSGeometry.cSectors * 512,
721 NULL);
722
723 RTMemFree(pNewBlock);
724 }
725 else
726 {
727 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
728 rc = parallelsFileWriteSync(pImage, uOffsetInFile, pvBuf, cbBuf, NULL);
729 }
730 }
731
732 if (pcbWriteProcess)
733 *pcbWriteProcess = cbBuf;
734
735 /* Stay on the safe side. Do not run the risk of confusing the higher
736 * level, as that can be pretty lethal to image consistency. */
737 *pcbPreRead = 0;
738 *pcbPostRead = 0;
739
740out:
741 LogFlowFunc(("returns %Rrc\n", rc));
742 return rc;
743}
744
745/** @copydoc VBOXHDDBACKEND::pfnFlush */
746static int parallelsFlush(void *pBackendData)
747{
748 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
749 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
750 int rc;
751
752 AssertPtr(pImage);
753
754 rc = parallelsFlushImage(pImage);
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::pfnGetSize */
775static uint64_t parallelsGetSize(void *pBackendData)
776{
777 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
778 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
779 uint64_t cb = 0;
780
781 AssertPtr(pImage);
782
783 if (pImage && pImage->pStorage)
784 cb = pImage->cbSize;
785
786 LogFlowFunc(("returns %llu\n", cb));
787 return cb;
788}
789
790/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
791static uint64_t parallelsGetFileSize(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->cbFileCurrent;
801
802 LogFlowFunc(("returns %lld\n", cb));
803 return cb;
804}
805
806/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
807static int parallelsGetPCHSGeometry(void *pBackendData,
808 PVDGEOMETRY pPCHSGeometry)
809{
810 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
811 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
812 int rc;
813
814 AssertPtr(pImage);
815
816 if (pImage)
817 {
818 if (pImage->PCHSGeometry.cCylinders)
819 {
820 *pPCHSGeometry = pImage->PCHSGeometry;
821 rc = VINF_SUCCESS;
822 }
823 else
824 rc = VERR_VD_GEOMETRY_NOT_SET;
825 }
826 else
827 rc = VERR_VD_NOT_OPENED;
828
829 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
830 return rc;
831}
832
833/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
834static int parallelsSetPCHSGeometry(void *pBackendData,
835 PCVDGEOMETRY pPCHSGeometry)
836{
837 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
838 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
839 int rc;
840
841 AssertPtr(pImage);
842
843 if (pImage)
844 {
845 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
846 {
847 rc = VERR_VD_IMAGE_READ_ONLY;
848 goto out;
849 }
850
851 pImage->PCHSGeometry = *pPCHSGeometry;
852 rc = VINF_SUCCESS;
853 }
854 else
855 rc = VERR_VD_NOT_OPENED;
856
857out:
858 LogFlowFunc(("returns %Rrc\n", rc));
859 return rc;
860}
861
862/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
863static int parallelsGetLCHSGeometry(void *pBackendData,
864 PVDGEOMETRY pLCHSGeometry)
865{
866 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
867 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
868 int rc;
869
870 AssertPtr(pImage);
871
872 if (pImage)
873 {
874 if (pImage->LCHSGeometry.cCylinders)
875 {
876 *pLCHSGeometry = pImage->LCHSGeometry;
877 rc = VINF_SUCCESS;
878 }
879 else
880 rc = VERR_VD_GEOMETRY_NOT_SET;
881 }
882 else
883 rc = VERR_VD_NOT_OPENED;
884
885 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
886 return rc;
887}
888
889/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
890static int parallelsSetLCHSGeometry(void *pBackendData,
891 PCVDGEOMETRY pLCHSGeometry)
892{
893 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
894 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
895 int rc;
896
897 AssertPtr(pImage);
898
899 if (pImage)
900 {
901 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
902 {
903 rc = VERR_VD_IMAGE_READ_ONLY;
904 goto out;
905 }
906
907 pImage->LCHSGeometry = *pLCHSGeometry;
908 rc = VINF_SUCCESS;
909 }
910 else
911 rc = VERR_VD_NOT_OPENED;
912
913out:
914 LogFlowFunc(("returns %Rrc\n", rc));
915 return rc;
916}
917
918/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
919static unsigned parallelsGetImageFlags(void *pBackendData)
920{
921 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
922 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
923 unsigned uImageFlags;
924
925 AssertPtr(pImage);
926
927 if (pImage)
928 uImageFlags = pImage->uImageFlags;
929 else
930 uImageFlags = 0;
931
932 LogFlowFunc(("returns %#x\n", uImageFlags));
933 return uImageFlags;
934}
935
936/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
937static unsigned parallelsGetOpenFlags(void *pBackendData)
938{
939 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
940 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
941 unsigned uOpenFlags;
942
943 AssertPtr(pImage);
944
945 if (pImage)
946 uOpenFlags = pImage->uOpenFlags;
947 else
948 uOpenFlags = 0;
949
950 LogFlowFunc(("returns %#x\n", uOpenFlags));
951 return uOpenFlags;
952}
953
954/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
955static int parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
956{
957 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
958 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
959 int rc;
960
961 /* Image must be opened and the new flags must be valid. */
962 /** @todo r=klaus add VD_OPEN_FLAGS_ASYNC_IO when async io has been tested */
963 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
964 {
965 rc = VERR_INVALID_PARAMETER;
966 goto out;
967 }
968
969 /* Implement this operation via reopening the image. */
970 parallelsFreeImage(pImage, false);
971 rc = parallelsOpenImage(pImage, uOpenFlags);
972
973out:
974 LogFlowFunc(("returns %Rrc\n", rc));
975 return rc;
976}
977
978/** @copydoc VBOXHDDBACKEND::pfnGetComment */
979static int parallelsGetComment(void *pBackendData, char *pszComment,
980 size_t cbComment)
981{
982 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
983 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
984 int rc;
985
986 AssertPtr(pImage);
987
988 if (pImage)
989 rc = VERR_NOT_SUPPORTED;
990 else
991 rc = VERR_VD_NOT_OPENED;
992
993 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
994 return rc;
995}
996
997/** @copydoc VBOXHDDBACKEND::pfnSetComment */
998static int parallelsSetComment(void *pBackendData, const char *pszComment)
999{
1000 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
1001 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1002 int rc;
1003
1004 AssertPtr(pImage);
1005
1006 if (pImage)
1007 {
1008 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1009 rc = VERR_VD_IMAGE_READ_ONLY;
1010 else
1011 rc = VERR_NOT_SUPPORTED;
1012 }
1013 else
1014 rc = VERR_VD_NOT_OPENED;
1015
1016 LogFlowFunc(("returns %Rrc\n", rc));
1017 return rc;
1018}
1019
1020/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
1021static int parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
1022{
1023 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1024 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1025 int rc;
1026
1027 AssertPtr(pImage);
1028
1029 if (pImage)
1030 rc = VERR_NOT_SUPPORTED;
1031 else
1032 rc = VERR_VD_NOT_OPENED;
1033
1034 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1035 return rc;
1036}
1037
1038/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
1039static int parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
1040{
1041 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1042 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1043 int rc;
1044
1045 AssertPtr(pImage);
1046
1047 if (pImage)
1048 {
1049 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1050 rc = VERR_NOT_SUPPORTED;
1051 else
1052 rc = VERR_VD_IMAGE_READ_ONLY;
1053 }
1054 else
1055 rc = VERR_VD_NOT_OPENED;
1056
1057 LogFlowFunc(("returns %Rrc\n", rc));
1058 return rc;
1059}
1060
1061/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1062static int parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1063{
1064 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1065 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1066 int rc;
1067
1068 AssertPtr(pImage);
1069
1070 if (pImage)
1071 rc = VERR_NOT_SUPPORTED;
1072 else
1073 rc = VERR_VD_NOT_OPENED;
1074
1075 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1076 return rc;
1077}
1078
1079/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1080static int parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1081{
1082 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1083 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1084 int rc;
1085
1086 AssertPtr(pImage);
1087
1088 if (pImage)
1089 {
1090 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1091 rc = VERR_NOT_SUPPORTED;
1092 else
1093 rc = VERR_VD_IMAGE_READ_ONLY;
1094 }
1095 else
1096 rc = VERR_VD_NOT_OPENED;
1097
1098 LogFlowFunc(("returns %Rrc\n", rc));
1099 return rc;
1100}
1101
1102/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1103static int parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
1104{
1105 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1106 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1107 int rc;
1108
1109 AssertPtr(pImage);
1110
1111 if (pImage)
1112 rc = VERR_NOT_SUPPORTED;
1113 else
1114 rc = VERR_VD_NOT_OPENED;
1115
1116 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1117 return rc;
1118}
1119
1120/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1121static int parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1122{
1123 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1124 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1125 int rc;
1126
1127 AssertPtr(pImage);
1128
1129 if (pImage)
1130 {
1131 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1132 rc = VERR_NOT_SUPPORTED;
1133 else
1134 rc = VERR_VD_IMAGE_READ_ONLY;
1135 }
1136 else
1137 rc = VERR_VD_NOT_OPENED;
1138
1139 LogFlowFunc(("returns %Rrc\n", rc));
1140 return rc;
1141}
1142
1143/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1144static int parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1145{
1146 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1147 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1148 int rc;
1149
1150 AssertPtr(pImage);
1151
1152 if (pImage)
1153 rc = VERR_NOT_SUPPORTED;
1154 else
1155 rc = VERR_VD_NOT_OPENED;
1156
1157 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1158 return rc;
1159}
1160
1161/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1162static int parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1163{
1164 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1165 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1166 int rc;
1167
1168 AssertPtr(pImage);
1169
1170 if (pImage)
1171 {
1172 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1173 rc = VERR_NOT_SUPPORTED;
1174 else
1175 rc = VERR_VD_IMAGE_READ_ONLY;
1176 }
1177 else
1178 rc = VERR_VD_NOT_OPENED;
1179
1180 LogFlowFunc(("returns %Rrc\n", rc));
1181 return rc;
1182}
1183
1184/** @copydoc VBOXHDDBACKEND::pfnDump */
1185static void parallelsDump(void *pBackendData)
1186{
1187 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1188
1189 AssertPtr(pImage);
1190 if (pImage)
1191 {
1192 parallelsMessage(pImage, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
1193 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1194 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
1195 }
1196}
1197
1198/** @copydoc VBOXHDDBACKEND::pfnIsAsyncIOSupported */
1199static bool parallelsIsAsyncIOSupported(void *pBackendData)
1200{
1201#if 0 /** @todo: Remove when tested */
1202 return true;
1203#else
1204 return false;
1205#endif
1206}
1207
1208/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
1209static int parallelsAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
1210 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
1211{
1212 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
1213 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
1214 int rc = VINF_SUCCESS;
1215 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1216 uint64_t uSector;
1217 uint64_t uOffsetInFile;
1218 uint32_t iIndexInAllocationTable;
1219
1220 AssertPtr(pImage);
1221 Assert(uOffset % 512 == 0);
1222 Assert(cbToRead % 512 == 0);
1223
1224 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
1225 {
1226 rc = parallelsFileReadUserAsync(pImage, uOffset, pIoCtx, cbToRead);
1227 }
1228 else
1229 {
1230 /* Calculate offset in the real file. */
1231 uSector = uOffset / 512;
1232 /* One chunk in the file is always one track big. */
1233 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
1234 uSector = uSector % pImage->PCHSGeometry.cSectors;
1235
1236 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
1237
1238 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
1239 {
1240 rc = VERR_VD_BLOCK_FREE;
1241 }
1242 else
1243 {
1244 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
1245 rc = parallelsFileReadUserAsync(pImage, uOffsetInFile, pIoCtx, cbToRead);
1246 }
1247 }
1248
1249 *pcbActuallyRead = cbToRead;
1250
1251 LogFlowFunc(("returns %Rrc\n", rc));
1252 return rc;
1253}
1254
1255/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
1256static int parallelsAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
1257 PVDIOCTX pIoCtx,
1258 size_t *pcbWriteProcess, size_t *pcbPreRead,
1259 size_t *pcbPostRead, unsigned fWrite)
1260{
1261 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
1262 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
1263 int rc = VINF_SUCCESS;
1264 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1265 uint64_t uSector;
1266 uint64_t uOffsetInFile;
1267 uint32_t iIndexInAllocationTable;
1268
1269 AssertPtr(pImage);
1270 Assert(uOffset % 512 == 0);
1271 Assert(cbToWrite % 512 == 0);
1272
1273 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
1274 {
1275 rc = parallelsFileWriteUserAsync(pImage, uOffset, pIoCtx, cbToWrite, NULL, NULL);
1276 }
1277 else
1278 {
1279 /* Calculate offset in the real file. */
1280 uSector = uOffset / 512;
1281 /* One chunk in the file is always one track big. */
1282 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
1283 uSector = uSector % pImage->PCHSGeometry.cSectors;
1284
1285 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
1286
1287 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
1288 {
1289 if (fWrite & VD_WRITE_NO_ALLOC)
1290 {
1291 *pcbPreRead = uSector * 512;
1292 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
1293
1294 if (pcbWriteProcess)
1295 *pcbWriteProcess = cbToWrite;
1296 return VERR_VD_BLOCK_FREE;
1297 }
1298
1299 /* Allocate new chunk in the file. */
1300 Assert(uSector == 0);
1301 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
1302 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
1303 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
1304 pImage->fAllocationBitmapChanged = true;
1305 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
1306
1307 /*
1308 * Write the new block at the current end of the file.
1309 */
1310 rc = parallelsFileWriteUserAsync(pImage, uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
1311 if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
1312 {
1313 /* Write the changed allocation bitmap entry. */
1314 /** @todo: Error handling. */
1315 rc = parallelsFileWriteMetaAsync(pImage,
1316 sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
1317 &pImage->pAllocationBitmap[iIndexInAllocationTable],
1318 sizeof(uint32_t), pIoCtx,
1319 NULL, NULL);
1320 }
1321 }
1322 else
1323 {
1324 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
1325 rc = parallelsFileWriteUserAsync(pImage, uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
1326 }
1327 }
1328
1329 if (pcbWriteProcess)
1330 *pcbWriteProcess = cbToWrite;
1331
1332 LogFlowFunc(("returns %Rrc\n", rc));
1333 return rc;
1334}
1335
1336/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
1337static int parallelsAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
1338{
1339 int rc = VINF_SUCCESS;
1340 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1341
1342 LogFlowFunc(("pImage=#%p\n", pImage));
1343
1344 /* Flush the file, everything is up to date already. */
1345 rc = parallelsFileFlushAsync(pImage, pIoCtx, NULL, NULL);
1346
1347 LogFlowFunc(("returns %Rrc\n", rc));
1348 return rc;
1349}
1350
1351
1352VBOXHDDBACKEND g_ParallelsBackend =
1353{
1354 /* pszBackendName */
1355 "Parallels",
1356 /* cbSize */
1357 sizeof(VBOXHDDBACKEND),
1358 /* uBackendCaps */
1359 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1360 /* paFileExtensions */
1361 s_aParallelsFileExtensions,
1362 /* paConfigInfo */
1363 NULL,
1364 /* hPlugin */
1365 NIL_RTLDRMOD,
1366 /* pfnCheckIfValid */
1367 parallelsCheckIfValid,
1368 /* pfnOpen */
1369 parallelsOpen,
1370 /* pfnCreate */
1371 parallelsCreate,
1372 /* pfnRename */
1373 parallelsRename,
1374 /* pfnClose */
1375 parallelsClose,
1376 /* pfnRead */
1377 parallelsRead,
1378 /* pfnWrite */
1379 parallelsWrite,
1380 /* pfnFlush */
1381 parallelsFlush,
1382 /* pfnGetVersion */
1383 parallelsGetVersion,
1384 /* pfnGetSize */
1385 parallelsGetSize,
1386 /* pfnGetFileSize */
1387 parallelsGetFileSize,
1388 /* pfnGetPCHSGeometry */
1389 parallelsGetPCHSGeometry,
1390 /* pfnSetPCHSGeometry */
1391 parallelsSetPCHSGeometry,
1392 /* pfnGetLCHSGeometry */
1393 parallelsGetLCHSGeometry,
1394 /* pfnSetLCHSGeometry */
1395 parallelsSetLCHSGeometry,
1396 /* pfnGetImageFlags */
1397 parallelsGetImageFlags,
1398 /* pfnGetOpenFlags */
1399 parallelsGetOpenFlags,
1400 /* pfnSetOpenFlags */
1401 parallelsSetOpenFlags,
1402 /* pfnGetComment */
1403 parallelsGetComment,
1404 /* pfnSetComment */
1405 parallelsSetComment,
1406 /* pfnGetUuid */
1407 parallelsGetUuid,
1408 /* pfnSetUuid */
1409 parallelsSetUuid,
1410 /* pfnGetModificationUuid */
1411 parallelsGetModificationUuid,
1412 /* pfnSetModificationUuid */
1413 parallelsSetModificationUuid,
1414 /* pfnGetParentUuid */
1415 parallelsGetParentUuid,
1416 /* pfnSetParentUuid */
1417 parallelsSetParentUuid,
1418 /* pfnGetParentModificationUuid */
1419 parallelsGetParentModificationUuid,
1420 /* pfnSetParentModificationUuid */
1421 parallelsSetParentModificationUuid,
1422 /* pfnDump */
1423 parallelsDump,
1424 /* pfnGetTimeStamp */
1425 NULL,
1426 /* pfnGetParentTimeStamp */
1427 NULL,
1428 /* pfnSetParentTimeStamp */
1429 NULL,
1430 /* pfnGetParentFilename */
1431 NULL,
1432 /* pfnSetParentFilename */
1433 NULL,
1434 /* pfnIsAsyncIOSupported */
1435 parallelsIsAsyncIOSupported,
1436 /* pfnAsyncRead */
1437 parallelsAsyncRead,
1438 /* pfnAsyncWrite */
1439 parallelsAsyncWrite,
1440 /* pfnAsyncFlush */
1441 parallelsAsyncFlush,
1442 /* pfnComposeLocation */
1443 genericFileComposeLocation,
1444 /* pfnComposeName */
1445 genericFileComposeName,
1446 /* pfnCompact */
1447 NULL,
1448 /* pfnResize */
1449 NULL
1450};
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