VirtualBox

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

Last change on this file since 48935 was 48743, checked in by vboxsync, 11 years ago

Storage/VD: Add support for different sector sizes (only opening and reading and writing images, not creating them with a sector size other than 512 bytes)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.1 KB
Line 
1/* $Id: Parallels.cpp 48743 2013-09-27 18:19:03Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2013 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 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 rc = 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 pImage->uOpenFlags = uOpenFlags;
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));
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 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));
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));
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, size_t cbToRead,
606 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
607{
608 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
609 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
610 int rc = VINF_SUCCESS;
611 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
612 uint64_t uSector;
613 uint64_t uOffsetInFile;
614 uint32_t iIndexInAllocationTable;
615
616 AssertPtr(pImage);
617 Assert(uOffset % 512 == 0);
618 Assert(cbToRead % 512 == 0);
619
620 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
621 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
622 pIoCtx, cbToRead);
623 else
624 {
625 /* Calculate offset in the real file. */
626 uSector = uOffset / 512;
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 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
632
633 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
634 rc = VERR_VD_BLOCK_FREE;
635 else
636 {
637 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
638 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
639 pIoCtx, cbToRead);
640 }
641 }
642
643 *pcbActuallyRead = cbToRead;
644
645 LogFlowFunc(("returns %Rrc\n", rc));
646 return rc;
647}
648
649/** @copydoc VBOXHDDBACKEND::pfnWrite */
650static int parallelsWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
651 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
652 size_t *pcbPostRead, unsigned fWrite)
653{
654 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
655 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
656 int rc = VINF_SUCCESS;
657 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
658 uint64_t uSector;
659 uint64_t uOffsetInFile;
660 uint32_t iIndexInAllocationTable;
661
662 AssertPtr(pImage);
663 Assert(uOffset % 512 == 0);
664 Assert(cbToWrite % 512 == 0);
665
666 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
667 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
668 pIoCtx, cbToWrite, NULL, NULL);
669 else
670 {
671 /* Calculate offset in the real file. */
672 uSector = uOffset / 512;
673 /* One chunk in the file is always one track big. */
674 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
675 uSector = uSector % pImage->PCHSGeometry.cSectors;
676
677 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
678
679 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
680 {
681 if (fWrite & VD_WRITE_NO_ALLOC)
682 {
683 *pcbPreRead = uSector * 512;
684 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
685
686 if (pcbWriteProcess)
687 *pcbWriteProcess = cbToWrite;
688 return VERR_VD_BLOCK_FREE;
689 }
690
691 /* Allocate new chunk in the file. */
692 Assert(uSector == 0);
693 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
694 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
695 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
696 pImage->fAllocationBitmapChanged = true;
697 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
698
699 /*
700 * Write the new block at the current end of the file.
701 */
702 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
703 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
704 if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
705 {
706 /* Write the changed allocation bitmap entry. */
707 /** @todo: Error handling. */
708 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
709 sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
710 &pImage->pAllocationBitmap[iIndexInAllocationTable],
711 sizeof(uint32_t), pIoCtx,
712 NULL, NULL);
713 }
714
715 *pcbPreRead = 0;
716 *pcbPostRead = 0;
717 }
718 else
719 {
720 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
721 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
722 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
723 }
724 }
725
726 if (pcbWriteProcess)
727 *pcbWriteProcess = cbToWrite;
728
729 LogFlowFunc(("returns %Rrc\n", rc));
730 return rc;
731}
732
733/** @copydoc VBOXHDDBACKEND::pfnFlush */
734static int parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
735{
736 int rc = VINF_SUCCESS;
737 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
738
739 LogFlowFunc(("pImage=#%p\n", pImage));
740
741 /* Flush the file, everything is up to date already. */
742 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
743
744 LogFlowFunc(("returns %Rrc\n", rc));
745 return rc;
746}
747
748/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
749static unsigned parallelsGetVersion(void *pBackendData)
750{
751 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
752 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
753
754 AssertPtr(pImage);
755
756 if (pImage)
757 return PARALLELS_DISK_VERSION;
758 else
759 return 0;
760}
761
762/** @copydoc VBOXHDDBACKEND::pfnGetSectorSize */
763static uint32_t parallelsGetSectorSize(void *pBackendData)
764{
765 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
766 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
767 uint32_t cb = 0;
768
769 AssertPtr(pImage);
770
771 if (pImage && pImage->pStorage)
772 cb = 512;
773
774 LogFlowFunc(("returns %llu\n", cb));
775 return cb;
776}
777
778/** @copydoc VBOXHDDBACKEND::pfnGetSize */
779static uint64_t parallelsGetSize(void *pBackendData)
780{
781 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
782 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
783 uint64_t cb = 0;
784
785 AssertPtr(pImage);
786
787 if (pImage && pImage->pStorage)
788 cb = pImage->cbSize;
789
790 LogFlowFunc(("returns %llu\n", cb));
791 return cb;
792}
793
794/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
795static uint64_t parallelsGetFileSize(void *pBackendData)
796{
797 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
798 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
799 uint64_t cb = 0;
800
801 AssertPtr(pImage);
802
803 if (pImage && pImage->pStorage)
804 cb = pImage->cbFileCurrent;
805
806 LogFlowFunc(("returns %lld\n", cb));
807 return cb;
808}
809
810/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
811static int parallelsGetPCHSGeometry(void *pBackendData,
812 PVDGEOMETRY pPCHSGeometry)
813{
814 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
815 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
816 int rc;
817
818 AssertPtr(pImage);
819
820 if (pImage)
821 {
822 if (pImage->PCHSGeometry.cCylinders)
823 {
824 *pPCHSGeometry = pImage->PCHSGeometry;
825 rc = VINF_SUCCESS;
826 }
827 else
828 rc = VERR_VD_GEOMETRY_NOT_SET;
829 }
830 else
831 rc = VERR_VD_NOT_OPENED;
832
833 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
834 return rc;
835}
836
837/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
838static int parallelsSetPCHSGeometry(void *pBackendData,
839 PCVDGEOMETRY pPCHSGeometry)
840{
841 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
842 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
843 int rc;
844
845 AssertPtr(pImage);
846
847 if (pImage)
848 {
849 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
850 {
851 rc = VERR_VD_IMAGE_READ_ONLY;
852 goto out;
853 }
854
855 pImage->PCHSGeometry = *pPCHSGeometry;
856 rc = VINF_SUCCESS;
857 }
858 else
859 rc = VERR_VD_NOT_OPENED;
860
861out:
862 LogFlowFunc(("returns %Rrc\n", rc));
863 return rc;
864}
865
866/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
867static int parallelsGetLCHSGeometry(void *pBackendData,
868 PVDGEOMETRY pLCHSGeometry)
869{
870 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
871 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
872 int rc;
873
874 AssertPtr(pImage);
875
876 if (pImage)
877 {
878 if (pImage->LCHSGeometry.cCylinders)
879 {
880 *pLCHSGeometry = pImage->LCHSGeometry;
881 rc = VINF_SUCCESS;
882 }
883 else
884 rc = VERR_VD_GEOMETRY_NOT_SET;
885 }
886 else
887 rc = VERR_VD_NOT_OPENED;
888
889 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
890 return rc;
891}
892
893/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
894static int parallelsSetLCHSGeometry(void *pBackendData,
895 PCVDGEOMETRY pLCHSGeometry)
896{
897 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
898 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
899 int rc;
900
901 AssertPtr(pImage);
902
903 if (pImage)
904 {
905 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
906 {
907 rc = VERR_VD_IMAGE_READ_ONLY;
908 goto out;
909 }
910
911 pImage->LCHSGeometry = *pLCHSGeometry;
912 rc = VINF_SUCCESS;
913 }
914 else
915 rc = VERR_VD_NOT_OPENED;
916
917out:
918 LogFlowFunc(("returns %Rrc\n", rc));
919 return rc;
920}
921
922/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
923static unsigned parallelsGetImageFlags(void *pBackendData)
924{
925 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
926 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
927 unsigned uImageFlags;
928
929 AssertPtr(pImage);
930
931 if (pImage)
932 uImageFlags = pImage->uImageFlags;
933 else
934 uImageFlags = 0;
935
936 LogFlowFunc(("returns %#x\n", uImageFlags));
937 return uImageFlags;
938}
939
940/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
941static unsigned parallelsGetOpenFlags(void *pBackendData)
942{
943 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
944 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
945 unsigned uOpenFlags;
946
947 AssertPtr(pImage);
948
949 if (pImage)
950 uOpenFlags = pImage->uOpenFlags;
951 else
952 uOpenFlags = 0;
953
954 LogFlowFunc(("returns %#x\n", uOpenFlags));
955 return uOpenFlags;
956}
957
958/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
959static int parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
960{
961 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
962 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
963 int rc;
964
965 /* Image must be opened and the new flags must be valid. */
966 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
967 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
968 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
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
1204
1205VBOXHDDBACKEND g_ParallelsBackend =
1206{
1207 /* pszBackendName */
1208 "Parallels",
1209 /* cbSize */
1210 sizeof(VBOXHDDBACKEND),
1211 /* uBackendCaps */
1212 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
1213 /* paFileExtensions */
1214 s_aParallelsFileExtensions,
1215 /* paConfigInfo */
1216 NULL,
1217 /* hPlugin */
1218 NIL_RTLDRMOD,
1219 /* pfnCheckIfValid */
1220 parallelsCheckIfValid,
1221 /* pfnOpen */
1222 parallelsOpen,
1223 /* pfnCreate */
1224 parallelsCreate,
1225 /* pfnRename */
1226 parallelsRename,
1227 /* pfnClose */
1228 parallelsClose,
1229 /* pfnRead */
1230 parallelsRead,
1231 /* pfnWrite */
1232 parallelsWrite,
1233 /* pfnFlush */
1234 parallelsFlush,
1235 /* pfnDiscard */
1236 NULL,
1237 /* pfnGetVersion */
1238 parallelsGetVersion,
1239 /* pfnGetSectorSize */
1240 parallelsGetSectorSize,
1241 /* pfnGetSize */
1242 parallelsGetSize,
1243 /* pfnGetFileSize */
1244 parallelsGetFileSize,
1245 /* pfnGetPCHSGeometry */
1246 parallelsGetPCHSGeometry,
1247 /* pfnSetPCHSGeometry */
1248 parallelsSetPCHSGeometry,
1249 /* pfnGetLCHSGeometry */
1250 parallelsGetLCHSGeometry,
1251 /* pfnSetLCHSGeometry */
1252 parallelsSetLCHSGeometry,
1253 /* pfnGetImageFlags */
1254 parallelsGetImageFlags,
1255 /* pfnGetOpenFlags */
1256 parallelsGetOpenFlags,
1257 /* pfnSetOpenFlags */
1258 parallelsSetOpenFlags,
1259 /* pfnGetComment */
1260 parallelsGetComment,
1261 /* pfnSetComment */
1262 parallelsSetComment,
1263 /* pfnGetUuid */
1264 parallelsGetUuid,
1265 /* pfnSetUuid */
1266 parallelsSetUuid,
1267 /* pfnGetModificationUuid */
1268 parallelsGetModificationUuid,
1269 /* pfnSetModificationUuid */
1270 parallelsSetModificationUuid,
1271 /* pfnGetParentUuid */
1272 parallelsGetParentUuid,
1273 /* pfnSetParentUuid */
1274 parallelsSetParentUuid,
1275 /* pfnGetParentModificationUuid */
1276 parallelsGetParentModificationUuid,
1277 /* pfnSetParentModificationUuid */
1278 parallelsSetParentModificationUuid,
1279 /* pfnDump */
1280 parallelsDump,
1281 /* pfnGetTimeStamp */
1282 NULL,
1283 /* pfnGetParentTimeStamp */
1284 NULL,
1285 /* pfnSetParentTimeStamp */
1286 NULL,
1287 /* pfnGetParentFilename */
1288 NULL,
1289 /* pfnSetParentFilename */
1290 NULL,
1291 /* pfnComposeLocation */
1292 genericFileComposeLocation,
1293 /* pfnComposeName */
1294 genericFileComposeName,
1295 /* pfnCompact */
1296 NULL,
1297 /* pfnResize */
1298 NULL,
1299 /* pfnRepair */
1300 NULL
1301};
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