VirtualBox

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

Last change on this file since 30888 was 30864, checked in by vboxsync, 15 years ago

VD/Parallels: Implement async I/O support. Completely untestet right now, thatswhy disabled

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