VirtualBox

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

Last change on this file since 40739 was 38469, checked in by vboxsync, 13 years ago

VD: Interface cleanup. Merge the two involved structures (generic interface descriptor and callback table) into one, remove the duplicated interface wrappers in the backends and move the interface definitions into separate headers separating public and private interfaces.

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