VirtualBox

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

Last change on this file since 43667 was 40948, checked in by vboxsync, 12 years ago

Storage/Parallels: Include asm.h for ASMByteSwapU32 used when converting endianess on big endian architectures

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

© 2023 Oracle
ContactPrivacy policyTerms of Use