VirtualBox

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

Last change on this file since 65381 was 64277, checked in by vboxsync, 8 years ago

doxygen fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.0 KB
Line 
1/* $Id: Parallels.cpp 64277 2016-10-14 11:21:53Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2016 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#include "VDBackends.h"
32
33#define PARALLELS_HEADER_MAGIC "WithoutFreeSpace"
34#define PARALLELS_DISK_VERSION 2
35
36/** The header of the parallels disk. */
37#pragma pack(1)
38typedef struct ParallelsHeader
39{
40 /** The magic header to identify a parallels hdd image. */
41 char HeaderIdentifier[16];
42 /** The version of the disk image. */
43 uint32_t uVersion;
44 /** The number of heads the hdd has. */
45 uint32_t cHeads;
46 /** Number of cylinders. */
47 uint32_t cCylinders;
48 /** Number of sectors per track. */
49 uint32_t cSectorsPerTrack;
50 /** Number of entries in the allocation bitmap. */
51 uint32_t cEntriesInAllocationBitmap;
52 /** Total number of sectors. */
53 uint32_t cSectors;
54 /** Padding. */
55 char Padding[24];
56} ParallelsHeader;
57#pragma pack()
58
59/**
60 * Parallels image structure.
61 */
62typedef struct PARALLELSIMAGE
63{
64 /** Image file name. */
65 const char *pszFilename;
66 /** Opaque storage handle. */
67 PVDIOSTORAGE pStorage;
68
69 /** Pointer to the per-disk VD interface list. */
70 PVDINTERFACE pVDIfsDisk;
71 /** Pointer to the per-image VD interface list. */
72 PVDINTERFACE pVDIfsImage;
73 /** Error interface. */
74 PVDINTERFACEERROR pIfError;
75 /** I/O interface. */
76 PVDINTERFACEIOINT pIfIo;
77
78 /** Open flags passed by VBoxHDD layer. */
79 unsigned uOpenFlags;
80 /** Image flags defined during creation or determined during open. */
81 unsigned uImageFlags;
82 /** Total size of the image. */
83 uint64_t cbSize;
84
85 /** Physical geometry of this image. */
86 VDGEOMETRY PCHSGeometry;
87 /** Logical geometry of this image. */
88 VDGEOMETRY LCHSGeometry;
89
90 /** Pointer to the allocation bitmap. */
91 uint32_t *pAllocationBitmap;
92 /** Entries in the allocation bitmap. */
93 uint64_t cAllocationBitmapEntries;
94 /** Flag whether the allocation bitmap was changed. */
95 bool fAllocationBitmapChanged;
96 /** Current file size. */
97 uint64_t cbFileCurrent;
98} PARALLELSIMAGE, *PPARALLELSIMAGE;
99
100
101/*********************************************************************************************************************************
102* Static Variables *
103*********************************************************************************************************************************/
104
105/** NULL-terminated array of supported file extensions. */
106static const VDFILEEXTENSION s_aParallelsFileExtensions[] =
107{
108 {"hdd", VDTYPE_HDD},
109 {NULL, VDTYPE_INVALID}
110};
111
112/***************************************************
113 * Internal functions *
114 **************************************************/
115
116/**
117 * Internal. Flush image data to disk.
118 */
119static int parallelsFlushImage(PPARALLELSIMAGE pImage)
120{
121 int rc = VINF_SUCCESS;
122
123 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
124 return VINF_SUCCESS;
125
126 if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
127 && (pImage->fAllocationBitmapChanged))
128 {
129 pImage->fAllocationBitmapChanged = false;
130 /* Write the allocation bitmap to the file. */
131 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
132 sizeof(ParallelsHeader), pImage->pAllocationBitmap,
133 pImage->cAllocationBitmapEntries * sizeof(uint32_t));
134 if (RT_FAILURE(rc))
135 return rc;
136 }
137
138 /* Flush file. */
139 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
140
141 LogFlowFunc(("returns %Rrc\n", rc));
142 return rc;
143}
144
145/**
146 * Internal. Free all allocated space for representing an image except pImage,
147 * and optionally delete the image from disk.
148 */
149static int parallelsFreeImage(PPARALLELSIMAGE pImage, bool fDelete)
150{
151 int rc = VINF_SUCCESS;
152
153 /* Freeing a never allocated image (e.g. because the open failed) is
154 * not signalled as an error. After all nothing bad happens. */
155 if (pImage)
156 {
157 if (pImage->pStorage)
158 {
159 /* No point updating the file that is deleted anyway. */
160 if (!fDelete)
161 parallelsFlushImage(pImage);
162
163 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
164 pImage->pStorage = NULL;
165 }
166
167 if (pImage->pAllocationBitmap)
168 {
169 RTMemFree(pImage->pAllocationBitmap);
170 pImage->pAllocationBitmap = NULL;
171 }
172
173 if (fDelete && pImage->pszFilename)
174 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
175 }
176
177 return rc;
178}
179
180static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
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 int rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
188 VDOpenFlagsToFileOpenFlags(uOpenFlags,
189 false /* fCreate */),
190 &pImage->pStorage);
191 if (RT_SUCCESS(rc))
192 {
193 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbFileCurrent);
194 if (RT_SUCCESS(rc)
195 && !(pImage->cbFileCurrent % 512))
196 {
197 ParallelsHeader parallelsHeader;
198
199 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0,
200 &parallelsHeader, sizeof(parallelsHeader));
201 if (RT_SUCCESS(rc))
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 *pszSuffix = RTPathSuffix(pImage->pszFilename);
207 if (!strcmp(pszSuffix, ".hdd"))
208 {
209 /* This is a fixed size image. */
210 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
211 pImage->cbSize = pImage->cbFileCurrent;
212
213 pImage->PCHSGeometry.cHeads = 16;
214 pImage->PCHSGeometry.cSectors = 63;
215 uint64_t cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
216 pImage->PCHSGeometry.cCylinders = (uint32_t)cCylinders;
217 }
218 else
219 rc = VERR_VD_PARALLELS_INVALID_HEADER;
220 }
221 else
222 {
223 if ( parallelsHeader.uVersion == PARALLELS_DISK_VERSION
224 && parallelsHeader.cEntriesInAllocationBitmap <= (1 << 30))
225 {
226 Log(("cSectors=%u\n", parallelsHeader.cSectors));
227 pImage->cbSize = ((uint64_t)parallelsHeader.cSectors) * 512;
228 pImage->uImageFlags = VD_IMAGE_FLAGS_NONE;
229 pImage->PCHSGeometry.cCylinders = parallelsHeader.cCylinders;
230 pImage->PCHSGeometry.cHeads = parallelsHeader.cHeads;
231 pImage->PCHSGeometry.cSectors = parallelsHeader.cSectorsPerTrack;
232 pImage->cAllocationBitmapEntries = parallelsHeader.cEntriesInAllocationBitmap;
233 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ((uint32_t)pImage->cAllocationBitmapEntries * sizeof(uint32_t));
234 if (RT_LIKELY(pImage->pAllocationBitmap))
235 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
236 sizeof(ParallelsHeader), pImage->pAllocationBitmap,
237 pImage->cAllocationBitmapEntries * sizeof(uint32_t));
238 else
239 rc = VERR_NO_MEMORY;
240 }
241 else
242 rc = VERR_NOT_SUPPORTED;
243 }
244 }
245 }
246 else if (RT_SUCCESS(rc))
247 rc = VERR_VD_PARALLELS_INVALID_HEADER;
248 }
249
250 LogFlowFunc(("returns %Rrc\n", rc));
251 return rc;
252}
253
254/**
255 * Internal: Create a parallels image.
256 */
257static int parallelsCreateImage(PPARALLELSIMAGE pImage, uint64_t cbSize,
258 unsigned uImageFlags, const char *pszComment,
259 PCVDGEOMETRY pPCHSGeometry,
260 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
261 PFNVDPROGRESS pfnProgress, void *pvUser,
262 unsigned uPercentStart, unsigned uPercentSpan)
263{
264 RT_NOREF1(pszComment);
265 int rc = VINF_SUCCESS;
266 int32_t fOpen;
267
268 if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
269 {
270 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
271 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
272 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
273
274 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
275 pImage->uImageFlags = uImageFlags;
276 pImage->PCHSGeometry = *pPCHSGeometry;
277 pImage->LCHSGeometry = *pLCHSGeometry;
278 if (!pImage->PCHSGeometry.cCylinders)
279 {
280 /* Set defaults. */
281 pImage->PCHSGeometry.cSectors = 63;
282 pImage->PCHSGeometry.cHeads = 16;
283 pImage->PCHSGeometry.cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
284 }
285
286 /* Create image file. */
287 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
288 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
289 if (RT_SUCCESS(rc))
290 {
291 if (pfnProgress)
292 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
293
294 /* Setup image state. */
295 pImage->cbSize = cbSize;
296 pImage->cAllocationBitmapEntries = cbSize / 512 / pImage->PCHSGeometry.cSectors;
297 if (pImage->cAllocationBitmapEntries * pImage->PCHSGeometry.cSectors * 512 < cbSize)
298 pImage->cAllocationBitmapEntries++;
299 pImage->fAllocationBitmapChanged = true;
300 pImage->cbFileCurrent = sizeof(ParallelsHeader) + pImage->cAllocationBitmapEntries * sizeof(uint32_t);
301 /* Round to next sector boundary. */
302 pImage->cbFileCurrent += 512 - pImage->cbFileCurrent % 512;
303 Assert(!(pImage->cbFileCurrent % 512));
304 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ(pImage->cAllocationBitmapEntries * sizeof(uint32_t));
305 if (pImage->pAllocationBitmap)
306 {
307 ParallelsHeader Header;
308
309 memcpy(Header.HeaderIdentifier, PARALLELS_HEADER_MAGIC, sizeof(Header.HeaderIdentifier));
310 Header.uVersion = RT_H2LE_U32(PARALLELS_DISK_VERSION);
311 Header.cHeads = RT_H2LE_U32(pImage->PCHSGeometry.cHeads);
312 Header.cCylinders = RT_H2LE_U32(pImage->PCHSGeometry.cCylinders);
313 Header.cSectorsPerTrack = RT_H2LE_U32(pImage->PCHSGeometry.cSectors);
314 Header.cEntriesInAllocationBitmap = RT_H2LE_U32(pImage->cAllocationBitmapEntries);
315 Header.cSectors = RT_H2LE_U32(pImage->cbSize / 512);
316 memset(Header.Padding, 0, sizeof(Header.Padding));
317
318 /* Write header and allocation bitmap. */
319 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbFileCurrent);
320 if (RT_SUCCESS(rc))
321 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0,
322 &Header, sizeof(Header));
323 if (RT_SUCCESS(rc))
324 rc = parallelsFlushImage(pImage); /* Writes the allocation bitmap. */
325 }
326 else
327 rc = VERR_NO_MEMORY;
328 }
329 else
330 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Parallels: cannot create image '%s'"), pImage->pszFilename);
331 }
332 else
333 rc = vdIfError(pImage->pIfError, VERR_VD_INVALID_TYPE, RT_SRC_POS, N_("Parallels: cannot create fixed image '%s'. Create a raw image"), pImage->pszFilename);
334
335 if (RT_SUCCESS(rc) && pfnProgress)
336 pfnProgress(pvUser, uPercentStart + uPercentSpan);
337
338 if (RT_FAILURE(rc))
339 parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
340 return rc;
341}
342
343/** @copydoc VDIMAGEBACKEND::pfnProbe */
344static DECLCALLBACK(int) parallelsProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
345 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
346{
347 RT_NOREF1(pVDIfsDisk);
348 int rc;
349 PVDIOSTORAGE pStorage;
350 ParallelsHeader parallelsHeader;
351
352 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
353 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
354
355 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
356 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
357 false /* fCreate */),
358 &pStorage);
359 if (RT_FAILURE(rc))
360 return rc;
361
362 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &parallelsHeader,
363 sizeof(ParallelsHeader));
364 if (RT_SUCCESS(rc))
365 {
366 if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
367 && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
368 rc = VINF_SUCCESS;
369 else
370 {
371 /*
372 * The image may be an fixed size image.
373 * Unfortunately fixed sized parallels images
374 * are just raw files hence no magic header to
375 * check for.
376 * The code succeeds if the file is a multiple
377 * of 512 and if the file extensions is *.hdd
378 */
379 uint64_t cbFile;
380 char *pszSuffix;
381
382 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
383 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
384 {
385 vdIfIoIntFileClose(pIfIo, pStorage);
386 return VERR_VD_PARALLELS_INVALID_HEADER;
387 }
388
389 pszSuffix = RTPathSuffix(pszFilename);
390 if (!pszSuffix || strcmp(pszSuffix, ".hdd"))
391 rc = VERR_VD_PARALLELS_INVALID_HEADER;
392 else
393 rc = VINF_SUCCESS;
394 }
395 }
396
397 if (RT_SUCCESS(rc))
398 *penmType = VDTYPE_HDD;
399
400 vdIfIoIntFileClose(pIfIo, pStorage);
401 return rc;
402}
403
404/** @copydoc VDIMAGEBACKEND::pfnOpen */
405static DECLCALLBACK(int) parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
406 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
407 VDTYPE enmType, void **ppBackendData)
408{
409 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
410 int rc;
411 PPARALLELSIMAGE pImage;
412
413 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
414
415 /* Check parameters. */
416 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
417 AssertReturn(VALID_PTR(pszFilename) && *pszFilename, VERR_INVALID_PARAMETER);
418
419 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
420 if (RT_LIKELY(pImage))
421 {
422 pImage->pszFilename = pszFilename;
423 pImage->pStorage = NULL;
424 pImage->pVDIfsDisk = pVDIfsDisk;
425 pImage->pVDIfsImage = pVDIfsImage;
426 pImage->fAllocationBitmapChanged = false;
427
428 rc = parallelsOpenImage(pImage, uOpenFlags);
429 if (RT_SUCCESS(rc))
430 *ppBackendData = pImage;
431 else
432 RTMemFree(pImage);
433 }
434 else
435 rc = VERR_NO_MEMORY;
436
437 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
438 return rc;
439}
440
441/** @copydoc VDIMAGEBACKEND::pfnCreate */
442static DECLCALLBACK(int) parallelsCreate(const char *pszFilename, uint64_t cbSize,
443 unsigned uImageFlags, const char *pszComment,
444 PCVDGEOMETRY pPCHSGeometry,
445 PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
446 unsigned uOpenFlags, unsigned uPercentStart,
447 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
448 PVDINTERFACE pVDIfsImage,
449 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
450 void **ppBackendData)
451{
452 RT_NOREF1(pUuid);
453 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 enmType=%u ppBackendData=%#p",
454 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
455
456 /* Check the VD container type. */
457 if (enmType != VDTYPE_HDD)
458 return VERR_VD_INVALID_TYPE;
459
460 /* Check arguments. */
461 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
462 AssertReturn( VALID_PTR(pszFilename)
463 && *pszFilename
464 && VALID_PTR(pPCHSGeometry)
465 && VALID_PTR(pLCHSGeometry), VERR_INVALID_PARAMETER);
466
467 int rc = VINF_SUCCESS;
468 PPARALLELSIMAGE pImage;
469 PFNVDPROGRESS pfnProgress = NULL;
470 void *pvUser = NULL;
471 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
472 if (pIfProgress)
473 {
474 pfnProgress = pIfProgress->pfnProgress;
475 pvUser = pIfProgress->Core.pvUser;
476 }
477
478 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
479 if (RT_LIKELY(pImage))
480 {
481 pImage->pszFilename = pszFilename;
482 pImage->pStorage = NULL;
483 pImage->pVDIfsDisk = pVDIfsDisk;
484 pImage->pVDIfsImage = pVDIfsImage;
485
486 rc = parallelsCreateImage(pImage, cbSize, uImageFlags, pszComment,
487 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
488 pfnProgress, pvUser, uPercentStart, uPercentSpan);
489 if (RT_SUCCESS(rc))
490 {
491 /* So far the image is opened in read/write mode. Make sure the
492 * image is opened in read-only mode if the caller requested that. */
493 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
494 {
495 parallelsFreeImage(pImage, false);
496 rc = parallelsOpenImage(pImage, uOpenFlags);
497 }
498
499 if (RT_SUCCESS(rc))
500 *ppBackendData = pImage;
501 }
502
503 if (RT_FAILURE(rc))
504 RTMemFree(pImage);
505 }
506 else
507 rc = VERR_NO_MEMORY;
508
509 LogFlowFunc(("returns %Rrc\n", rc));
510 return rc;
511}
512
513/** @copydoc VDIMAGEBACKEND::pfnRename */
514static DECLCALLBACK(int) parallelsRename(void *pBackendData, const char *pszFilename)
515{
516 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
517 int rc = VINF_SUCCESS;
518 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
519
520 /* Check arguments. */
521 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
522
523 /* Close the image. */
524 rc = parallelsFreeImage(pImage, false);
525 if (RT_SUCCESS(rc))
526 {
527 /* Rename the file. */
528 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
529 if (RT_SUCCESS(rc))
530 {
531 /* Update pImage with the new information. */
532 pImage->pszFilename = pszFilename;
533
534 /* Open the old image with new name. */
535 rc = parallelsOpenImage(pImage, pImage->uOpenFlags);
536 }
537 else
538 {
539 /* The move failed, try to reopen the original image. */
540 int rc2 = parallelsOpenImage(pImage, pImage->uOpenFlags);
541 if (RT_FAILURE(rc2))
542 rc = rc2;
543 }
544 }
545
546 LogFlowFunc(("returns %Rrc\n", rc));
547 return rc;
548}
549
550/** @copydoc VDIMAGEBACKEND::pfnClose */
551static DECLCALLBACK(int) parallelsClose(void *pBackendData, bool fDelete)
552{
553 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
554 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
555 int rc = parallelsFreeImage(pImage, fDelete);
556 RTMemFree(pImage);
557
558 LogFlowFunc(("returns %Rrc\n", rc));
559 return rc;
560}
561
562/** @copydoc VDIMAGEBACKEND::pfnRead */
563static DECLCALLBACK(int) parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
564 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
565{
566 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
567 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
568 int rc = VINF_SUCCESS;
569 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
570 uint64_t uSector;
571 uint64_t uOffsetInFile;
572 uint32_t iIndexInAllocationTable;
573
574 AssertPtr(pImage);
575 Assert(uOffset % 512 == 0);
576 Assert(cbToRead % 512 == 0);
577
578 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
579 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
580 pIoCtx, cbToRead);
581 else
582 {
583 /* Calculate offset in the real file. */
584 uSector = uOffset / 512;
585 /* One chunk in the file is always one track big. */
586 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
587 uSector = uSector % pImage->PCHSGeometry.cSectors;
588
589 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
590
591 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
592 rc = VERR_VD_BLOCK_FREE;
593 else
594 {
595 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
596 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
597 pIoCtx, cbToRead);
598 }
599 }
600
601 *pcbActuallyRead = cbToRead;
602
603 LogFlowFunc(("returns %Rrc\n", rc));
604 return rc;
605}
606
607/** @copydoc VDIMAGEBACKEND::pfnWrite */
608static DECLCALLBACK(int) parallelsWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
609 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
610 size_t *pcbPostRead, unsigned fWrite)
611{
612 LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
613 pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
614 int rc = VINF_SUCCESS;
615 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
616 uint64_t uSector;
617 uint64_t uOffsetInFile;
618 uint32_t iIndexInAllocationTable;
619
620 AssertPtr(pImage);
621 Assert(uOffset % 512 == 0);
622 Assert(cbToWrite % 512 == 0);
623
624 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
625 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
626 pIoCtx, cbToWrite, NULL, NULL);
627 else
628 {
629 /* Calculate offset in the real file. */
630 uSector = uOffset / 512;
631 /* One chunk in the file is always one track big. */
632 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
633 uSector = uSector % pImage->PCHSGeometry.cSectors;
634
635 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
636
637 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
638 {
639 if (fWrite & VD_WRITE_NO_ALLOC)
640 {
641 *pcbPreRead = uSector * 512;
642 *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
643
644 if (pcbWriteProcess)
645 *pcbWriteProcess = cbToWrite;
646 return VERR_VD_BLOCK_FREE;
647 }
648
649 /* Allocate new chunk in the file. */
650 Assert(uSector == 0);
651 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
652 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
653 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
654 pImage->fAllocationBitmapChanged = true;
655 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
656
657 /*
658 * Write the new block at the current end of the file.
659 */
660 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
661 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
662 if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
663 {
664 /* Write the changed allocation bitmap entry. */
665 /** @todo Error handling. */
666 rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
667 sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
668 &pImage->pAllocationBitmap[iIndexInAllocationTable],
669 sizeof(uint32_t), pIoCtx,
670 NULL, NULL);
671 }
672
673 *pcbPreRead = 0;
674 *pcbPostRead = 0;
675 }
676 else
677 {
678 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
679 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
680 uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
681 }
682 }
683
684 if (pcbWriteProcess)
685 *pcbWriteProcess = cbToWrite;
686
687 LogFlowFunc(("returns %Rrc\n", rc));
688 return rc;
689}
690
691/** @copydoc VDIMAGEBACKEND::pfnFlush */
692static DECLCALLBACK(int) parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
693{
694 int rc = VINF_SUCCESS;
695 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
696
697 LogFlowFunc(("pImage=#%p\n", pImage));
698
699 /* Flush the file, everything is up to date already. */
700 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
701
702 LogFlowFunc(("returns %Rrc\n", rc));
703 return rc;
704}
705
706/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
707static DECLCALLBACK(unsigned) parallelsGetVersion(void *pBackendData)
708{
709 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
710 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
711
712 AssertPtrReturn(pImage, 0);
713
714 return PARALLELS_DISK_VERSION;
715}
716
717/** @copydoc VDIMAGEBACKEND::pfnGetSectorSize */
718static DECLCALLBACK(uint32_t) parallelsGetSectorSize(void *pBackendData)
719{
720 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
721 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
722 uint32_t cb = 0;
723
724 AssertPtrReturn(pImage, 0);
725
726 if (pImage->pStorage)
727 cb = 512;
728
729 LogFlowFunc(("returns %llu\n", cb));
730 return cb;
731}
732
733/** @copydoc VDIMAGEBACKEND::pfnGetSize */
734static DECLCALLBACK(uint64_t) parallelsGetSize(void *pBackendData)
735{
736 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
737 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
738 uint64_t cb = 0;
739
740 AssertPtrReturn(pImage, 0);
741
742 if (pImage->pStorage)
743 cb = pImage->cbSize;
744
745 LogFlowFunc(("returns %llu\n", cb));
746 return cb;
747}
748
749/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
750static DECLCALLBACK(uint64_t) parallelsGetFileSize(void *pBackendData)
751{
752 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
753 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
754 uint64_t cb = 0;
755
756 AssertPtrReturn(pImage, 0);
757
758 if (pImage->pStorage)
759 cb = pImage->cbFileCurrent;
760
761 LogFlowFunc(("returns %lld\n", cb));
762 return cb;
763}
764
765/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
766static DECLCALLBACK(int) parallelsGetPCHSGeometry(void *pBackendData,
767 PVDGEOMETRY pPCHSGeometry)
768{
769 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
770 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
771 int rc = VINF_SUCCESS;
772
773 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
774
775 if (pImage->PCHSGeometry.cCylinders)
776 *pPCHSGeometry = pImage->PCHSGeometry;
777 else
778 rc = VERR_VD_GEOMETRY_NOT_SET;
779
780 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
781 return rc;
782}
783
784/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
785static DECLCALLBACK(int) parallelsSetPCHSGeometry(void *pBackendData,
786 PCVDGEOMETRY pPCHSGeometry)
787{
788 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData,
789 pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
790 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
791 int rc = VINF_SUCCESS;
792
793 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
794
795 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
796 rc = VERR_VD_IMAGE_READ_ONLY;
797 else
798 pImage->PCHSGeometry = *pPCHSGeometry;
799
800 LogFlowFunc(("returns %Rrc\n", rc));
801 return rc;
802}
803
804/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
805static DECLCALLBACK(int) parallelsGetLCHSGeometry(void *pBackendData,
806 PVDGEOMETRY pLCHSGeometry)
807{
808 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
809 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
810 int rc = VINF_SUCCESS;
811
812 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
813
814 if (pImage->LCHSGeometry.cCylinders)
815 *pLCHSGeometry = pImage->LCHSGeometry;
816 else
817 rc = VERR_VD_GEOMETRY_NOT_SET;
818
819 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
820 return rc;
821}
822
823/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
824static DECLCALLBACK(int) parallelsSetLCHSGeometry(void *pBackendData,
825 PCVDGEOMETRY pLCHSGeometry)
826{
827 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
828 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
829 int rc = VINF_SUCCESS;
830
831 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
832
833 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
834 rc = VERR_VD_IMAGE_READ_ONLY;
835 else
836 pImage->LCHSGeometry = *pLCHSGeometry;
837
838 LogFlowFunc(("returns %Rrc\n", rc));
839 return rc;
840}
841
842/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
843static DECLCALLBACK(unsigned) parallelsGetImageFlags(void *pBackendData)
844{
845 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
846 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
847
848 AssertPtrReturn(pImage, 0);
849
850 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
851 return pImage->uImageFlags;
852}
853
854/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
855static DECLCALLBACK(unsigned) parallelsGetOpenFlags(void *pBackendData)
856{
857 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
858 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
859
860 AssertPtrReturn(pImage, 0);
861
862 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
863 return pImage->uOpenFlags;
864}
865
866/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
867static DECLCALLBACK(int) parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
868{
869 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
870 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
871 int rc = VINF_SUCCESS;
872
873 /* Image must be opened and the new flags must be valid. */
874 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
875 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
876 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
877 rc = VERR_INVALID_PARAMETER;
878 else
879 {
880 /* Implement this operation via reopening the image. */
881 parallelsFreeImage(pImage, false);
882 rc = parallelsOpenImage(pImage, uOpenFlags);
883 }
884
885 LogFlowFunc(("returns %Rrc\n", rc));
886 return rc;
887}
888
889/** @copydoc VDIMAGEBACKEND::pfnGetComment */
890static DECLCALLBACK(int) parallelsGetComment(void *pBackendData, char *pszComment,
891 size_t cbComment)
892{
893 RT_NOREF2(pszComment, cbComment);
894 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
895 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
896
897 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
898
899 LogFlowFunc(("returns %Rrc comment='%s'\n", VERR_NOT_SUPPORTED, pszComment));
900 return VERR_NOT_SUPPORTED;
901}
902
903/** @copydoc VDIMAGEBACKEND::pfnSetComment */
904static DECLCALLBACK(int) parallelsSetComment(void *pBackendData, const char *pszComment)
905{
906 RT_NOREF1(pszComment);
907 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
908 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
909
910 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
911
912 int rc;
913 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
914 rc = VERR_VD_IMAGE_READ_ONLY;
915 else
916 rc = VERR_NOT_SUPPORTED;
917
918 LogFlowFunc(("returns %Rrc\n", rc));
919 return rc;
920}
921
922/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
923static DECLCALLBACK(int) parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
924{
925 RT_NOREF1(pUuid);
926 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
927 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
928
929 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
930
931 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
932 return VERR_NOT_SUPPORTED;
933}
934
935/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
936static DECLCALLBACK(int) parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
937{
938 RT_NOREF1(pUuid);
939 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
940 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
941
942 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
943
944 int rc;
945 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
946 rc = VERR_VD_IMAGE_READ_ONLY;
947 else
948 rc = VERR_NOT_SUPPORTED;
949
950 LogFlowFunc(("returns %Rrc\n", rc));
951 return rc;
952}
953
954/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
955static DECLCALLBACK(int) parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
956{
957 RT_NOREF1(pUuid);
958 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
959 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
960
961 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
962
963 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
964 return VERR_NOT_SUPPORTED;
965}
966
967/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
968static DECLCALLBACK(int) parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
969{
970 RT_NOREF1(pUuid);
971 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
972 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
973
974 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
975
976 int rc;
977 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
978 rc = VERR_VD_IMAGE_READ_ONLY;
979 else
980 rc = VERR_NOT_SUPPORTED;
981
982 LogFlowFunc(("returns %Rrc\n", rc));
983 return rc;
984}
985
986/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
987static DECLCALLBACK(int) parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
988{
989 RT_NOREF1(pUuid);
990 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
991 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
992
993 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
994
995 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
996 return VERR_NOT_SUPPORTED;
997}
998
999/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
1000static DECLCALLBACK(int) parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1001{
1002 RT_NOREF1(pUuid);
1003 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1004 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1005
1006 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1007
1008 int rc;
1009 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1010 rc = VERR_VD_IMAGE_READ_ONLY;
1011 else
1012 rc = VERR_NOT_SUPPORTED;
1013
1014 LogFlowFunc(("returns %Rrc\n", rc));
1015 return rc;
1016}
1017
1018/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
1019static DECLCALLBACK(int) parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1020{
1021 RT_NOREF1(pUuid);
1022 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1023 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1024
1025 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1026
1027 int rc;
1028 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1029 rc = VERR_VD_IMAGE_READ_ONLY;
1030 else
1031 rc = VERR_NOT_SUPPORTED;
1032
1033 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1034 return rc;
1035}
1036
1037/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
1038static DECLCALLBACK(int) parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1039{
1040 RT_NOREF1(pUuid);
1041 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1042 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1043
1044 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
1045
1046 int rc;
1047 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1048 rc = VERR_VD_IMAGE_READ_ONLY;
1049 else
1050 rc = VERR_NOT_SUPPORTED;
1051
1052 LogFlowFunc(("returns %Rrc\n", rc));
1053 return rc;
1054}
1055
1056/** @copydoc VDIMAGEBACKEND::pfnDump */
1057static DECLCALLBACK(void) parallelsDump(void *pBackendData)
1058{
1059 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1060
1061 AssertPtrReturnVoid(pImage);
1062 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
1063 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1064 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
1065}
1066
1067
1068
1069const VDIMAGEBACKEND g_ParallelsBackend =
1070{
1071 /* u32Version */
1072 VD_IMGBACKEND_VERSION,
1073 /* pszBackendName */
1074 "Parallels",
1075 /* uBackendCaps */
1076 VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
1077 /* paFileExtensions */
1078 s_aParallelsFileExtensions,
1079 /* paConfigInfo */
1080 NULL,
1081 /* pfnProbe */
1082 parallelsProbe,
1083 /* pfnOpen */
1084 parallelsOpen,
1085 /* pfnCreate */
1086 parallelsCreate,
1087 /* pfnRename */
1088 parallelsRename,
1089 /* pfnClose */
1090 parallelsClose,
1091 /* pfnRead */
1092 parallelsRead,
1093 /* pfnWrite */
1094 parallelsWrite,
1095 /* pfnFlush */
1096 parallelsFlush,
1097 /* pfnDiscard */
1098 NULL,
1099 /* pfnGetVersion */
1100 parallelsGetVersion,
1101 /* pfnGetSectorSize */
1102 parallelsGetSectorSize,
1103 /* pfnGetSize */
1104 parallelsGetSize,
1105 /* pfnGetFileSize */
1106 parallelsGetFileSize,
1107 /* pfnGetPCHSGeometry */
1108 parallelsGetPCHSGeometry,
1109 /* pfnSetPCHSGeometry */
1110 parallelsSetPCHSGeometry,
1111 /* pfnGetLCHSGeometry */
1112 parallelsGetLCHSGeometry,
1113 /* pfnSetLCHSGeometry */
1114 parallelsSetLCHSGeometry,
1115 /* pfnGetImageFlags */
1116 parallelsGetImageFlags,
1117 /* pfnGetOpenFlags */
1118 parallelsGetOpenFlags,
1119 /* pfnSetOpenFlags */
1120 parallelsSetOpenFlags,
1121 /* pfnGetComment */
1122 parallelsGetComment,
1123 /* pfnSetComment */
1124 parallelsSetComment,
1125 /* pfnGetUuid */
1126 parallelsGetUuid,
1127 /* pfnSetUuid */
1128 parallelsSetUuid,
1129 /* pfnGetModificationUuid */
1130 parallelsGetModificationUuid,
1131 /* pfnSetModificationUuid */
1132 parallelsSetModificationUuid,
1133 /* pfnGetParentUuid */
1134 parallelsGetParentUuid,
1135 /* pfnSetParentUuid */
1136 parallelsSetParentUuid,
1137 /* pfnGetParentModificationUuid */
1138 parallelsGetParentModificationUuid,
1139 /* pfnSetParentModificationUuid */
1140 parallelsSetParentModificationUuid,
1141 /* pfnDump */
1142 parallelsDump,
1143 /* pfnGetTimestamp */
1144 NULL,
1145 /* pfnGetParentTimestamp */
1146 NULL,
1147 /* pfnSetParentTimestamp */
1148 NULL,
1149 /* pfnGetParentFilename */
1150 NULL,
1151 /* pfnSetParentFilename */
1152 NULL,
1153 /* pfnComposeLocation */
1154 genericFileComposeLocation,
1155 /* pfnComposeName */
1156 genericFileComposeName,
1157 /* pfnCompact */
1158 NULL,
1159 /* pfnResize */
1160 NULL,
1161 /* pfnRepair */
1162 NULL,
1163 /* pfnTraverseMetadata */
1164 NULL,
1165 /* u32VersionEnd */
1166 VD_IMGBACKEND_VERSION
1167};
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