VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/ParallelsHDDCore.cpp@ 33426

Last change on this file since 33426 was 33258, checked in by vboxsync, 14 years ago

Removed unreferenced label.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.1 KB
Line 
1/* $Id: ParallelsHDDCore.cpp 33258 2010-10-20 12:22:21Z 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/VBoxHDD-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 char *const s_apszParallelsFileExtensions[] =
108{
109 "hdd",
110 NULL
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)
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 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
474 return rc;
475}
476
477/** @copydoc VBOXHDDBACKEND::pfnOpen */
478static int parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
479 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
480 void **ppBackendData)
481{
482 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
483 int rc;
484 PPARALLELSIMAGE pImage;
485
486 /* Check open flags. All valid flags are supported. */
487 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
488 {
489 rc = VERR_INVALID_PARAMETER;
490 goto out;
491 }
492
493 /* Check remaining arguments. */
494 if ( !VALID_PTR(pszFilename)
495 || !*pszFilename)
496 {
497 rc = VERR_INVALID_PARAMETER;
498 goto out;
499 }
500
501 /** @todo r=klaus why this duplicate check, async is not claimed... */
502 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
503 {
504 rc = VERR_NOT_SUPPORTED;
505 goto out;
506 }
507
508 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
509 if (!pImage)
510 {
511 rc = VERR_NO_MEMORY;
512 goto out;
513 }
514
515 pImage->pszFilename = pszFilename;
516 pImage->pStorage = NULL;
517 pImage->pVDIfsDisk = pVDIfsDisk;
518 pImage->pVDIfsImage = pVDIfsImage;
519 pImage->fAllocationBitmapChanged = false;
520
521 rc = parallelsOpenImage(pImage, uOpenFlags);
522 if (RT_SUCCESS(rc))
523 *ppBackendData = pImage;
524 else
525 RTMemFree(pImage);
526
527out:
528 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
529 return rc;
530}
531
532/** @copydoc VBOXHDDBACKEND::pfnCreate */
533static int parallelsCreate(const char *pszFilename, uint64_t cbSize,
534 unsigned uImageFlags, const char *pszComment,
535 PCVDGEOMETRY pPCHSGeometry,
536 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
537 unsigned uOpenFlags, unsigned uPercentStart,
538 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
539 PVDINTERFACE pVDIfsImage,
540 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
541{
542 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));
543 int rc = VERR_NOT_IMPLEMENTED;
544
545 LogFlowFunc(("returns %Rrc\n", rc));
546 return rc;
547}
548
549/** @copydoc VBOXHDDBACKEND::pfnRename */
550static int parallelsRename(void *pBackendData, const char *pszFilename)
551{
552 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
553 int rc = VINF_SUCCESS;
554 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
555
556 /* Check arguments. */
557 if ( !pImage
558 || !pszFilename
559 || !*pszFilename)
560 {
561 rc = VERR_INVALID_PARAMETER;
562 goto out;
563 }
564
565 /* Close the image. */
566 rc = parallelsFreeImage(pImage, false);
567 if (RT_FAILURE(rc))
568 goto out;
569
570 /* Rename the file. */
571 rc = parallelsFileMove(pImage, pImage->pszFilename, pszFilename, 0);
572 if (RT_FAILURE(rc))
573 {
574 /* The move failed, try to reopen the original image. */
575 int rc2 = parallelsOpenImage(pImage, pImage->uOpenFlags);
576 if (RT_FAILURE(rc2))
577 rc = rc2;
578
579 goto out;
580 }
581
582 /* Update pImage with the new information. */
583 pImage->pszFilename = pszFilename;
584
585 /* Open the old image with new name. */
586 rc = parallelsOpenImage(pImage, pImage->uOpenFlags);
587 if (RT_FAILURE(rc))
588 goto out;
589
590out:
591 LogFlowFunc(("returns %Rrc\n", rc));
592 return rc;
593}
594
595/** @copydoc VBOXHDDBACKEND::pfnClose */
596static int parallelsClose(void *pBackendData, bool fDelete)
597{
598 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
599 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
600 int rc;
601
602 rc = parallelsFreeImage(pImage, fDelete);
603 RTMemFree(pImage);
604
605 LogFlowFunc(("returns %Rrc\n", rc));
606 return rc;
607}
608
609/** @copydoc VBOXHDDBACKEND::pfnRead */
610static int parallelsRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
611 size_t cbBuf, size_t *pcbActuallyRead)
612{
613 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbBuf=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbActuallyRead));
614 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
615 int rc = VINF_SUCCESS;
616 uint64_t uSector;
617 uint64_t uOffsetInFile;
618 uint32_t iIndexInAllocationTable;
619
620 AssertPtr(pImage);
621 Assert(uOffset % 512 == 0);
622 Assert(cbBuf % 512 == 0);
623
624 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
625 {
626 rc = parallelsFileReadSync(pImage, uOffset, pvBuf, cbBuf, NULL);
627 }
628 else
629 {
630 /* Calculate offset in the real file. */
631 uSector = uOffset / 512;
632 /* One chunk in the file is always one track big. */
633 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
634 uSector = uSector % pImage->PCHSGeometry.cSectors;
635
636 cbBuf = RT_MIN(cbBuf, (pImage->PCHSGeometry.cSectors - uSector)*512);
637
638 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
639 {
640 rc = VERR_VD_BLOCK_FREE;
641 }
642 else
643 {
644 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
645 rc = parallelsFileReadSync(pImage, uOffsetInFile, pvBuf, cbBuf, NULL);
646 }
647 }
648
649 if (RT_SUCCESS(rc))
650 {
651 if (pcbActuallyRead)
652 *pcbActuallyRead = cbBuf;
653
654 Log2(("parallelsRead: off=%#llx pvBuf=%p cbBuf=%d\n"
655 "%.*Rhxd\n",
656 uOffset, pvBuf, cbBuf, cbBuf, pvBuf));
657 }
658
659 LogFlowFunc(("returns %Rrc\n", rc));
660 return rc;
661}
662
663/** @copydoc VBOXHDDBACKEND::pfnWrite */
664static int parallelsWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
665 size_t cbBuf, size_t *pcbWriteProcess,
666 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
667{
668 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbBuf=%zu pcbWriteProcess=%#p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbWriteProcess));
669 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
670 int rc = VINF_SUCCESS;
671 uint64_t uSector;
672 uint64_t uOffsetInFile;
673 uint32_t iIndexInAllocationTable;
674
675 AssertPtr(pImage);
676 Assert(uOffset % 512 == 0);
677 Assert(cbBuf % 512 == 0);
678
679 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
680 {
681 rc = parallelsFileWriteSync(pImage, uOffset, pvBuf, cbBuf, NULL);
682 }
683 else
684 {
685 /** Calculate offset in the real file. */
686 uSector = uOffset / 512;
687 /** One chunk in the file is always one track big. */
688 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
689 uSector = uSector % pImage->PCHSGeometry.cSectors;
690
691 cbBuf = RT_MIN(cbBuf, (pImage->PCHSGeometry.cSectors - uSector)*512);
692
693 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
694 {
695 /* Allocate new chunk in the file. */
696 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
697 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
698 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
699 pImage->fAllocationBitmapChanged = true;
700
701 uint8_t *pNewBlock = (uint8_t *)RTMemAllocZ(pImage->PCHSGeometry.cSectors * 512);
702
703 if (!pNewBlock)
704 {
705 rc = VERR_NO_MEMORY;
706 goto out;
707 }
708
709 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
710 memcpy(pNewBlock + (uOffset - ((uint64_t)iIndexInAllocationTable * pImage->PCHSGeometry.cSectors * 512)),
711 pvBuf, cbBuf);
712
713 /*
714 * Write the new block at the current end of the file.
715 */
716 rc = parallelsFileWriteSync(pImage, uOffsetInFile, pNewBlock,
717 pImage->PCHSGeometry.cSectors * 512,
718 NULL);
719
720 RTMemFree(pNewBlock);
721 }
722 else
723 {
724 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
725 rc = parallelsFileWriteSync(pImage, uOffsetInFile, pvBuf, cbBuf, NULL);
726 }
727 }
728
729 if (pcbWriteProcess)
730 *pcbWriteProcess = cbBuf;
731
732 /* Stay on the safe side. Do not run the risk of confusing the higher
733 * level, as that can be pretty lethal to image consistency. */
734 *pcbPreRead = 0;
735 *pcbPostRead = 0;
736
737out:
738 LogFlowFunc(("returns %Rrc\n", rc));
739 return rc;
740}
741
742/** @copydoc VBOXHDDBACKEND::pfnFlush */
743static int parallelsFlush(void *pBackendData)
744{
745 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
746 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
747 int rc;
748
749 AssertPtr(pImage);
750
751 rc = parallelsFlushImage(pImage);
752
753 LogFlowFunc(("returns %Rrc\n", rc));
754 return rc;
755}
756
757/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
758static unsigned parallelsGetVersion(void *pBackendData)
759{
760 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
761 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
762
763 AssertPtr(pImage);
764
765 if (pImage)
766 return PARALLELS_DISK_VERSION;
767 else
768 return 0;
769}
770
771/** @copydoc VBOXHDDBACKEND::pfnGetSize */
772static uint64_t parallelsGetSize(void *pBackendData)
773{
774 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
775 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
776 uint64_t cb = 0;
777
778 AssertPtr(pImage);
779
780 if (pImage && pImage->pStorage)
781 cb = pImage->cbSize;
782
783 LogFlowFunc(("returns %llu\n", cb));
784 return cb;
785}
786
787/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
788static uint64_t parallelsGetFileSize(void *pBackendData)
789{
790 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
791 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
792 uint64_t cb = 0;
793
794 AssertPtr(pImage);
795
796 if (pImage && pImage->pStorage)
797 cb = pImage->cbFileCurrent;
798
799 LogFlowFunc(("returns %lld\n", cb));
800 return cb;
801}
802
803/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
804static int parallelsGetPCHSGeometry(void *pBackendData,
805 PVDGEOMETRY pPCHSGeometry)
806{
807 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
808 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
809 int rc;
810
811 AssertPtr(pImage);
812
813 if (pImage)
814 {
815 if (pImage->PCHSGeometry.cCylinders)
816 {
817 *pPCHSGeometry = pImage->PCHSGeometry;
818 rc = VINF_SUCCESS;
819 }
820 else
821 rc = VERR_VD_GEOMETRY_NOT_SET;
822 }
823 else
824 rc = VERR_VD_NOT_OPENED;
825
826 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
827 return rc;
828}
829
830/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
831static int parallelsSetPCHSGeometry(void *pBackendData,
832 PCVDGEOMETRY pPCHSGeometry)
833{
834 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
835 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
836 int rc;
837
838 AssertPtr(pImage);
839
840 if (pImage)
841 {
842 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
843 {
844 rc = VERR_VD_IMAGE_READ_ONLY;
845 goto out;
846 }
847
848 pImage->PCHSGeometry = *pPCHSGeometry;
849 rc = VINF_SUCCESS;
850 }
851 else
852 rc = VERR_VD_NOT_OPENED;
853
854out:
855 LogFlowFunc(("returns %Rrc\n", rc));
856 return rc;
857}
858
859/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
860static int parallelsGetLCHSGeometry(void *pBackendData,
861 PVDGEOMETRY pLCHSGeometry)
862{
863 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
864 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
865 int rc;
866
867 AssertPtr(pImage);
868
869 if (pImage)
870 {
871 if (pImage->LCHSGeometry.cCylinders)
872 {
873 *pLCHSGeometry = pImage->LCHSGeometry;
874 rc = VINF_SUCCESS;
875 }
876 else
877 rc = VERR_VD_GEOMETRY_NOT_SET;
878 }
879 else
880 rc = VERR_VD_NOT_OPENED;
881
882 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
883 return rc;
884}
885
886/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
887static int parallelsSetLCHSGeometry(void *pBackendData,
888 PCVDGEOMETRY pLCHSGeometry)
889{
890 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
891 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
892 int rc;
893
894 AssertPtr(pImage);
895
896 if (pImage)
897 {
898 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
899 {
900 rc = VERR_VD_IMAGE_READ_ONLY;
901 goto out;
902 }
903
904 pImage->LCHSGeometry = *pLCHSGeometry;
905 rc = VINF_SUCCESS;
906 }
907 else
908 rc = VERR_VD_NOT_OPENED;
909
910out:
911 LogFlowFunc(("returns %Rrc\n", rc));
912 return rc;
913}
914
915/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
916static unsigned parallelsGetImageFlags(void *pBackendData)
917{
918 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
919 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
920 unsigned uImageFlags;
921
922 AssertPtr(pImage);
923
924 if (pImage)
925 uImageFlags = pImage->uImageFlags;
926 else
927 uImageFlags = 0;
928
929 LogFlowFunc(("returns %#x\n", uImageFlags));
930 return uImageFlags;
931}
932
933/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
934static unsigned parallelsGetOpenFlags(void *pBackendData)
935{
936 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
937 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
938 unsigned uOpenFlags;
939
940 AssertPtr(pImage);
941
942 if (pImage)
943 uOpenFlags = pImage->uOpenFlags;
944 else
945 uOpenFlags = 0;
946
947 LogFlowFunc(("returns %#x\n", uOpenFlags));
948 return uOpenFlags;
949}
950
951/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
952static int parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
953{
954 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
955 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
956 int rc;
957
958 /* Image must be opened and the new flags must be valid. */
959 /** @todo r=klaus add VD_OPEN_FLAGS_ASYNC_IO when async io has been tested */
960 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
961 {
962 rc = VERR_INVALID_PARAMETER;
963 goto out;
964 }
965
966 /* Implement this operation via reopening the image. */
967 parallelsFreeImage(pImage, true);
968 rc = parallelsOpenImage(pImage, uOpenFlags);
969
970out:
971 LogFlowFunc(("returns %Rrc\n", rc));
972 return rc;
973}
974
975/** @copydoc VBOXHDDBACKEND::pfnGetComment */
976static int parallelsGetComment(void *pBackendData, char *pszComment,
977 size_t cbComment)
978{
979 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
980 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
981 int rc;
982
983 AssertPtr(pImage);
984
985 if (pImage)
986 rc = VERR_NOT_SUPPORTED;
987 else
988 rc = VERR_VD_NOT_OPENED;
989
990 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
991 return rc;
992}
993
994/** @copydoc VBOXHDDBACKEND::pfnSetComment */
995static int parallelsSetComment(void *pBackendData, const char *pszComment)
996{
997 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
998 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
999 int rc;
1000
1001 AssertPtr(pImage);
1002
1003 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1004 {
1005 rc = VERR_VD_IMAGE_READ_ONLY;
1006 goto out;
1007 }
1008
1009 if (pImage)
1010 rc = VERR_NOT_SUPPORTED;
1011 else
1012 rc = VERR_VD_NOT_OPENED;
1013
1014out:
1015 LogFlowFunc(("returns %Rrc\n", rc));
1016 return rc;
1017}
1018
1019/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
1020static int parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
1021{
1022 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1023 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1024 int rc;
1025
1026 AssertPtr(pImage);
1027
1028 if (pImage)
1029 rc = VERR_NOT_SUPPORTED;
1030 else
1031 rc = VERR_VD_NOT_OPENED;
1032
1033 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1034 return rc;
1035}
1036
1037/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
1038static int parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
1039{
1040 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1041 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1042 int rc;
1043
1044 AssertPtr(pImage);
1045
1046 if (pImage)
1047 {
1048 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1049 rc = VERR_NOT_SUPPORTED;
1050 else
1051 rc = VERR_VD_IMAGE_READ_ONLY;
1052 }
1053 else
1054 rc = VERR_VD_NOT_OPENED;
1055
1056 LogFlowFunc(("returns %Rrc\n", rc));
1057 return rc;
1058}
1059
1060/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1061static int parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1062{
1063 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1064 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1065 int rc;
1066
1067 AssertPtr(pImage);
1068
1069 if (pImage)
1070 rc = VERR_NOT_SUPPORTED;
1071 else
1072 rc = VERR_VD_NOT_OPENED;
1073
1074 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1075 return rc;
1076}
1077
1078/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1079static int parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1080{
1081 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1082 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1083 int rc;
1084
1085 AssertPtr(pImage);
1086
1087 if (pImage)
1088 {
1089 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1090 rc = VERR_NOT_SUPPORTED;
1091 else
1092 rc = VERR_VD_IMAGE_READ_ONLY;
1093 }
1094 else
1095 rc = VERR_VD_NOT_OPENED;
1096
1097 LogFlowFunc(("returns %Rrc\n", rc));
1098 return rc;
1099}
1100
1101/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1102static int parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
1103{
1104 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1105 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1106 int rc;
1107
1108 AssertPtr(pImage);
1109
1110 if (pImage)
1111 rc = VERR_NOT_SUPPORTED;
1112 else
1113 rc = VERR_VD_NOT_OPENED;
1114
1115 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1116 return rc;
1117}
1118
1119/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1120static int parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1121{
1122 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1123 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1124 int rc;
1125
1126 AssertPtr(pImage);
1127
1128 if (pImage)
1129 {
1130 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1131 rc = VERR_NOT_SUPPORTED;
1132 else
1133 rc = VERR_VD_IMAGE_READ_ONLY;
1134 }
1135 else
1136 rc = VERR_VD_NOT_OPENED;
1137
1138 LogFlowFunc(("returns %Rrc\n", rc));
1139 return rc;
1140}
1141
1142/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1143static int parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1144{
1145 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1146 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1147 int rc;
1148
1149 AssertPtr(pImage);
1150
1151 if (pImage)
1152 rc = VERR_NOT_SUPPORTED;
1153 else
1154 rc = VERR_VD_NOT_OPENED;
1155
1156 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1157 return rc;
1158}
1159
1160/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1161static int parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1162{
1163 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1164 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1165 int rc;
1166
1167 AssertPtr(pImage);
1168
1169 if (pImage)
1170 {
1171 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1172 rc = VERR_NOT_SUPPORTED;
1173 else
1174 rc = VERR_VD_IMAGE_READ_ONLY;
1175 }
1176 else
1177 rc = VERR_VD_NOT_OPENED;
1178
1179 LogFlowFunc(("returns %Rrc\n", rc));
1180 return rc;
1181}
1182
1183/** @copydoc VBOXHDDBACKEND::pfnDump */
1184static void parallelsDump(void *pBackendData)
1185{
1186 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1187
1188 AssertPtr(pImage);
1189 if (pImage)
1190 {
1191 parallelsMessage(pImage, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
1192 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1193 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
1194 }
1195}
1196
1197/** @copydoc VBOXHDDBACKEND::pfnIsAsyncIOSupported */
1198static bool parallelsIsAsyncIOSupported(void *pBackendData)
1199{
1200#if 0 /** @todo: Remove when tested */
1201 return true;
1202#else
1203 return false;
1204#endif
1205}
1206
1207/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
1208static int parallelsAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
1209 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
1210{
1211 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
1212 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
1213 int rc = VINF_SUCCESS;
1214 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1215 uint64_t uSector;
1216 uint64_t uOffsetInFile;
1217 uint32_t iIndexInAllocationTable;
1218
1219 AssertPtr(pImage);
1220 Assert(uOffset % 512 == 0);
1221 Assert(cbToRead % 512 == 0);
1222
1223 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
1224 {
1225 rc = parallelsFileReadUserAsync(pImage, uOffset, pIoCtx, cbToRead);
1226 }
1227 else
1228 {
1229 /* Calculate offset in the real file. */
1230 uSector = uOffset / 512;
1231 /* One chunk in the file is always one track big. */
1232 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
1233 uSector = uSector % pImage->PCHSGeometry.cSectors;
1234
1235 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
1236
1237 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
1238 {
1239 rc = VERR_VD_BLOCK_FREE;
1240 }
1241 else
1242 {
1243 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
1244 rc = parallelsFileReadUserAsync(pImage, uOffsetInFile, pIoCtx, cbToRead);
1245 }
1246 }
1247
1248 *pcbActuallyRead = cbToRead;
1249
1250 LogFlowFunc(("returns %Rrc\n", rc));
1251 return rc;
1252}
1253
1254/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
1255static int parallelsAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
1256 PVDIOCTX pIoCtx,
1257 size_t *pcbWriteProcess, size_t *pcbPreRead,
1258 size_t *pcbPostRead, unsigned fWrite)
1259{
1260 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
1261 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
1262 int rc = VINF_SUCCESS;
1263 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1264 uint64_t uSector;
1265 uint64_t uOffsetInFile;
1266 uint32_t iIndexInAllocationTable;
1267
1268 AssertPtr(pImage);
1269 Assert(uOffset % 512 == 0);
1270 Assert(cbToWrite % 512 == 0);
1271
1272 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
1273 {
1274 rc = parallelsFileWriteUserAsync(pImage, uOffset, pIoCtx, cbToWrite, NULL, NULL);
1275 }
1276 else
1277 {
1278 /* Calculate offset in the real file. */
1279 uSector = uOffset / 512;
1280 /* One chunk in the file is always one track big. */
1281 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
1282 uSector = uSector % pImage->PCHSGeometry.cSectors;
1283
1284 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
1285
1286 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
1287 {
1288 if (fWrite & VD_WRITE_NO_ALLOC)
1289 {
1290 *pcbPreRead = uSector * 512;
1291 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
1292
1293 if (pcbWriteProcess)
1294 *pcbWriteProcess = cbToWrite;
1295 return VERR_VD_BLOCK_FREE;
1296 }
1297
1298 /* Allocate new chunk in the file. */
1299 Assert(uSector == 0);
1300 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
1301 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
1302 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
1303 pImage->fAllocationBitmapChanged = true;
1304 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
1305
1306 /*
1307 * Write the new block at the current end of the file.
1308 */
1309 rc = parallelsFileWriteUserAsync(pImage, uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
1310 if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
1311 {
1312 /* Write the changed allocation bitmap entry. */
1313 /** @todo: Error handling. */
1314 rc = parallelsFileWriteMetaAsync(pImage,
1315 sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
1316 &pImage->pAllocationBitmap[iIndexInAllocationTable],
1317 sizeof(uint32_t), pIoCtx,
1318 NULL, NULL);
1319 }
1320 }
1321 else
1322 {
1323 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
1324 rc = parallelsFileWriteUserAsync(pImage, uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
1325 }
1326 }
1327
1328 if (pcbWriteProcess)
1329 *pcbWriteProcess = cbToWrite;
1330
1331 LogFlowFunc(("returns %Rrc\n", rc));
1332 return rc;
1333}
1334
1335/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
1336static int parallelsAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
1337{
1338 int rc = VINF_SUCCESS;
1339 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1340
1341 LogFlowFunc(("pImage=#%p\n", pImage));
1342
1343 /* Flush the file, everything is up to date already. */
1344 rc = parallelsFileFlushAsync(pImage, pIoCtx, NULL, NULL);
1345
1346 LogFlowFunc(("returns %Rrc\n", rc));
1347 return rc;
1348}
1349
1350
1351VBOXHDDBACKEND g_ParallelsBackend =
1352{
1353 /* pszBackendName */
1354 "Parallels",
1355 /* cbSize */
1356 sizeof(VBOXHDDBACKEND),
1357 /* uBackendCaps */
1358 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1359 /* papszFileExtensions */
1360 s_apszParallelsFileExtensions,
1361 /* paConfigInfo */
1362 NULL,
1363 /* hPlugin */
1364 NIL_RTLDRMOD,
1365 /* pfnCheckIfValid */
1366 parallelsCheckIfValid,
1367 /* pfnOpen */
1368 parallelsOpen,
1369 /* pfnCreate */
1370 parallelsCreate,
1371 /* pfnRename */
1372 parallelsRename,
1373 /* pfnClose */
1374 parallelsClose,
1375 /* pfnRead */
1376 parallelsRead,
1377 /* pfnWrite */
1378 parallelsWrite,
1379 /* pfnFlush */
1380 parallelsFlush,
1381 /* pfnGetVersion */
1382 parallelsGetVersion,
1383 /* pfnGetSize */
1384 parallelsGetSize,
1385 /* pfnGetFileSize */
1386 parallelsGetFileSize,
1387 /* pfnGetPCHSGeometry */
1388 parallelsGetPCHSGeometry,
1389 /* pfnSetPCHSGeometry */
1390 parallelsSetPCHSGeometry,
1391 /* pfnGetLCHSGeometry */
1392 parallelsGetLCHSGeometry,
1393 /* pfnSetLCHSGeometry */
1394 parallelsSetLCHSGeometry,
1395 /* pfnGetImageFlags */
1396 parallelsGetImageFlags,
1397 /* pfnGetOpenFlags */
1398 parallelsGetOpenFlags,
1399 /* pfnSetOpenFlags */
1400 parallelsSetOpenFlags,
1401 /* pfnGetComment */
1402 parallelsGetComment,
1403 /* pfnSetComment */
1404 parallelsSetComment,
1405 /* pfnGetUuid */
1406 parallelsGetUuid,
1407 /* pfnSetUuid */
1408 parallelsSetUuid,
1409 /* pfnGetModificationUuid */
1410 parallelsGetModificationUuid,
1411 /* pfnSetModificationUuid */
1412 parallelsSetModificationUuid,
1413 /* pfnGetParentUuid */
1414 parallelsGetParentUuid,
1415 /* pfnSetParentUuid */
1416 parallelsSetParentUuid,
1417 /* pfnGetParentModificationUuid */
1418 parallelsGetParentModificationUuid,
1419 /* pfnSetParentModificationUuid */
1420 parallelsSetParentModificationUuid,
1421 /* pfnDump */
1422 parallelsDump,
1423 /* pfnGetTimeStamp */
1424 NULL,
1425 /* pfnGetParentTimeStamp */
1426 NULL,
1427 /* pfnSetParentTimeStamp */
1428 NULL,
1429 /* pfnGetParentFilename */
1430 NULL,
1431 /* pfnSetParentFilename */
1432 NULL,
1433 /* pfnIsAsyncIOSupported */
1434 parallelsIsAsyncIOSupported,
1435 /* pfnAsyncRead */
1436 parallelsAsyncRead,
1437 /* pfnAsyncWrite */
1438 parallelsAsyncWrite,
1439 /* pfnAsyncFlush */
1440 parallelsAsyncFlush,
1441 /* pfnComposeLocation */
1442 genericFileComposeLocation,
1443 /* pfnComposeName */
1444 genericFileComposeName,
1445 /* pfnCompact */
1446 NULL,
1447 /* pfnResize */
1448 NULL
1449};
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