VirtualBox

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

Last change on this file since 22432 was 21806, checked in by vboxsync, 15 years ago

Storage/VBoxHDD: resurrect the facility to dump information about disk images, and bare minimum fix for creating diff images.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.2 KB
Line 
1/* $Id: ParallelsHDDCore.cpp 21806 2009-07-27 10:14:11Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#define LOG_GROUP LOG_GROUP_VD_VMDK /** @todo: Logging group */
24#include "VBoxHDD-Internal.h"
25#include <VBox/err.h>
26
27#include <VBox/log.h>
28#include <iprt/assert.h>
29#include <iprt/alloc.h>
30#include <iprt/uuid.h>
31#include <iprt/file.h>
32#include <iprt/path.h>
33#include <iprt/string.h>
34
35#define PARALLELS_HEADER_MAGIC "WithoutFreeSpace"
36#define PARALLELS_DISK_VERSION 2
37
38/** The header of the parallels disk. */
39#pragma pack(1)
40typedef struct ParallelsHeader
41{
42 /** The magic header to identify a parallels hdd image. */
43 char HeaderIdentifier[16];
44 /** The version of the disk image. */
45 uint32_t uVersion;
46 /** The number of heads the hdd has. */
47 uint32_t cHeads;
48 /** Number of cylinders. */
49 uint32_t cCylinders;
50 /** Number of sectors per track. */
51 uint32_t cSectorsPerTrack;
52 /** Number of entries in the allocation bitmap. */
53 uint32_t cEntriesInAllocationBitmap;
54 /** Total number of sectors. */
55 uint32_t cSectors;
56 /** Padding. */
57 char Padding[24];
58} ParallelsHeader;
59#pragma pack()
60
61/**
62 * Parallels image structure.
63 */
64typedef struct PARALLELSIMAGE
65{
66 /** Pointer to the per-disk VD interface list. */
67 PVDINTERFACE pVDIfsDisk;
68 /** Error interface. */
69 PVDINTERFACE pInterfaceError;
70 /** Error interface callbacks. */
71 PVDINTERFACEERROR pInterfaceErrorCallbacks;
72
73 /** Image file name. */
74 const char *pszFilename;
75 /** File handle. */
76 RTFILE File;
77 /** Open flags passed by VBoxHD layer. */
78 unsigned uOpenFlags;
79 /** Image flags defined during creation or determined during open. */
80 unsigned uImageFlags;
81 /** Total size of the image. */
82 uint64_t cbSize;
83 /** Physical geometry of this image. */
84 PDMMEDIAGEOMETRY PCHSGeometry;
85 /** Logical geometry of this image. */
86 PDMMEDIAGEOMETRY LCHSGeometry;
87 /** Pointer to the allocation bitmap. */
88 uint32_t *pAllocationBitmap;
89 /** Entries in the allocation bitmap. */
90 uint64_t cAllocationBitmapEntries;
91 /** Flag whether the allocation bitmap was changed. */
92 bool fAllocationBitmapChanged;
93 /** Current file size. */
94 uint64_t cbFileCurrent;
95} PARALLELSIMAGE, *PPARALLELSIMAGE;
96
97/*******************************************************************************
98* Static Variables *
99*******************************************************************************/
100
101/** NULL-terminated array of supported file extensions. */
102static const char *const s_apszParallelsFileExtensions[] =
103{
104 "hdd",
105 NULL
106};
107
108/***************************************************
109 * Internal functions *
110 **************************************************/
111
112/**
113 * Internal: signal an error to the frontend.
114 */
115DECLINLINE(int) parallelsError(PPARALLELSIMAGE pImage, int rc, RT_SRC_POS_DECL,
116 const char *pszFormat, ...)
117{
118 va_list va;
119 va_start(va, pszFormat);
120 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
121 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
122 pszFormat, va);
123 va_end(va);
124 return rc;
125}
126
127static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
128{
129 int rc = VINF_SUCCESS;
130 RTFILE File;
131 ParallelsHeader parallelsHeader;
132
133 /* Try to get error interface. */
134 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
135 if (pImage->pInterfaceError)
136 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
137
138 rc = RTFileOpen(&File, pImage->pszFilename,
139 uOpenFlags & VD_OPEN_FLAGS_READONLY
140 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
141 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
142 if (RT_FAILURE(rc))
143 goto out;
144
145 pImage->File = File;
146
147 rc = RTFileGetSize(pImage->File, &pImage->cbFileCurrent);
148 if (RT_FAILURE(rc))
149 goto out;
150 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
151
152 rc = RTFileReadAt(File, 0, &parallelsHeader, sizeof(ParallelsHeader), NULL);
153 if (RT_FAILURE(rc))
154 goto out;
155
156 if (memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16))
157 {
158 /* Check if the file has hdd as extension. It is a fixed size raw image then. */
159 char *pszExtension = RTPathExt(pImage->pszFilename);
160 if (strcmp(pszExtension, ".hdd"))
161 {
162 rc = VERR_VD_GEN_INVALID_HEADER;
163 goto out;
164 }
165
166 /* This is a fixed size image. */
167 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
168 pImage->cbSize = pImage->cbFileCurrent;
169
170 pImage->PCHSGeometry.cHeads = 16;
171 pImage->PCHSGeometry.cSectors = 63;
172 uint64_t cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
173 pImage->PCHSGeometry.cCylinders = (uint32_t)cCylinders;
174 }
175 else
176 {
177 if (parallelsHeader.uVersion != PARALLELS_DISK_VERSION)
178 {
179 rc = VERR_NOT_SUPPORTED;
180 goto out;
181 }
182
183 if (parallelsHeader.cEntriesInAllocationBitmap > (1 << 30))
184 {
185 rc = VERR_NOT_SUPPORTED;
186 goto out;
187 }
188
189 Log(("cSectors=%u\n", parallelsHeader.cSectors));
190 pImage->cbSize = ((uint64_t)parallelsHeader.cSectors) * 512;
191 pImage->uImageFlags = VD_IMAGE_FLAGS_NONE;
192 pImage->cAllocationBitmapEntries = parallelsHeader.cEntriesInAllocationBitmap;
193 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ((uint32_t)pImage->cAllocationBitmapEntries * sizeof(uint32_t));
194 if (!pImage->pAllocationBitmap)
195 {
196 rc = VERR_NO_MEMORY;
197 goto out;
198 }
199
200 rc = RTFileReadAt(File, sizeof(ParallelsHeader), pImage->pAllocationBitmap,
201 pImage->cAllocationBitmapEntries * sizeof(uint32_t), NULL);
202 if (RT_FAILURE(rc))
203 goto out;
204
205 pImage->PCHSGeometry.cCylinders = parallelsHeader.cCylinders;
206 pImage->PCHSGeometry.cHeads = parallelsHeader.cHeads;
207 pImage->PCHSGeometry.cSectors = parallelsHeader.cSectorsPerTrack;
208 }
209
210out:
211 LogFlowFunc(("returns %Rrc\n", rc));
212 return rc;
213}
214
215static int parallelsFlushImage(PPARALLELSIMAGE pImage)
216{
217 LogFlowFunc(("pImage=#%p\n", pImage));
218 int rc = VINF_SUCCESS;
219
220 if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
221 && (pImage->fAllocationBitmapChanged))
222 {
223 pImage->fAllocationBitmapChanged = false;
224 /* Write the allocation bitmap to the file. */
225 rc = RTFileWriteAt(pImage->File, sizeof(ParallelsHeader),
226 pImage->pAllocationBitmap,
227 pImage->cAllocationBitmapEntries * sizeof(uint32_t),
228 NULL);
229 if (RT_FAILURE(rc))
230 return rc;
231 }
232
233 /* Flush file. */
234 rc = RTFileFlush(pImage->File);
235
236 LogFlowFunc(("returns %Rrc\n", rc));
237 return rc;
238}
239
240static void parallelsFreeImage(PPARALLELSIMAGE pImage, bool fDelete)
241{
242 (void)parallelsFlushImage(pImage);
243
244 if (pImage->pAllocationBitmap)
245 RTMemFree(pImage->pAllocationBitmap);
246
247 if (pImage->File != NIL_RTFILE)
248 RTFileClose(pImage->File);
249}
250
251/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
252static int parallelsCheckIfValid(const char *pszFilename)
253{
254 RTFILE File;
255 ParallelsHeader parallelsHeader;
256 int rc;
257
258 rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ);
259 if (RT_FAILURE(rc))
260 return VERR_VD_GEN_INVALID_HEADER;
261
262 rc = RTFileReadAt(File, 0, &parallelsHeader, sizeof(ParallelsHeader), NULL);
263 if (RT_FAILURE(rc))
264 {
265 rc = VERR_VD_GEN_INVALID_HEADER;
266 }
267 else
268 {
269 if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
270 && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
271 rc = VINF_SUCCESS;
272 else
273 {
274 /*
275 * The image may be an fixed size image.
276 * Unfortunately fixed sized parallels images
277 * are just raw files hence no magic header to
278 * check for.
279 * The code succeeds if the file is a multiple
280 * of 512 and if the file extensions is *.hdd
281 */
282 uint64_t cbFile;
283 char *pszExtension;
284
285 rc = RTFileGetSize(File, &cbFile);
286 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
287 {
288 RTFileClose(File);
289 return VERR_VD_GEN_INVALID_HEADER;
290 }
291
292 pszExtension = RTPathExt(pszFilename);
293 if (!pszExtension || strcmp(pszExtension, ".hdd"))
294 rc = VERR_VD_GEN_INVALID_HEADER;
295 else
296 rc = VINF_SUCCESS;
297 }
298 }
299
300 RTFileClose(File);
301 return rc;
302}
303
304/** @copydoc VBOXHDDBACKEND::pfnOpen */
305static int parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
306 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
307 void **ppBackendData)
308{
309 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
310 int rc;
311 PPARALLELSIMAGE pImage;
312
313 /* Check open flags. All valid flags are supported. */
314 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
315 {
316 rc = VERR_INVALID_PARAMETER;
317 goto out;
318 }
319
320 /* Check remaining arguments. */
321 if ( !VALID_PTR(pszFilename)
322 || !*pszFilename
323 || strchr(pszFilename, '"'))
324 {
325 rc = VERR_INVALID_PARAMETER;
326 goto out;
327 }
328
329 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
330 {
331 rc = VERR_NOT_SUPPORTED;
332 goto out;
333 }
334
335 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
336 if (!pImage)
337 {
338 rc = VERR_NO_MEMORY;
339 goto out;
340 }
341
342 pImage->File = NIL_RTFILE;
343 pImage->fAllocationBitmapChanged = false;
344 pImage->pszFilename = pszFilename;
345 pImage->pVDIfsDisk = pVDIfsDisk;
346
347 rc = parallelsOpenImage(pImage, uOpenFlags);
348 if (RT_SUCCESS(rc))
349 *ppBackendData = pImage;
350
351out:
352 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
353 return rc;
354}
355
356/** @copydoc VBOXHDDBACKEND::pfnCreate */
357static int parallelsCreate(const char *pszFilename, uint64_t cbSize,
358 unsigned uImageFlags, const char *pszComment,
359 PCPDMMEDIAGEOMETRY pPCHSGeometry,
360 PCPDMMEDIAGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
361 unsigned uOpenFlags, unsigned uPercentStart,
362 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
363 PVDINTERFACE pVDIfsImage, PVDINTERFACE pVDIfsOperation,
364 void **ppBackendData)
365{
366 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p ppBackendData=%#p", pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
367 return VERR_NOT_IMPLEMENTED;
368}
369
370/** @copydoc VBOXHDDBACKEND::pfnRename */
371static int parallelsRename(void *pBackendData, const char *pszFilename)
372{
373 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
374 return VERR_NOT_IMPLEMENTED;
375}
376
377/** @copydoc VBOXHDDBACKEND::pfnClose */
378static int parallelsClose(void *pBackendData, bool fDelete)
379{
380 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
381 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
382 int rc = VINF_SUCCESS;
383
384 /* Freeing a never allocated image (e.g. because the open failed) is
385 * not signalled as an error. After all nothing bad happens. */
386 if (pImage)
387 parallelsFreeImage(pImage, fDelete);
388
389 LogFlowFunc(("returns %Rrc\n", rc));
390 return rc;
391}
392
393/** @copydoc VBOXHDDBACKEND::pfnRead */
394static int parallelsRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
395 size_t cbToRead, size_t *pcbActuallyRead)
396{
397 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
398 int rc = VINF_SUCCESS;
399 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
400 uint64_t uSector;
401 uint64_t uOffsetInFile;
402 uint32_t iIndexInAllocationTable;
403
404 Assert(pImage);
405 Assert(uOffset % 512 == 0);
406 Assert(cbToRead % 512 == 0);
407
408 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
409 {
410 rc = RTFileReadAt(pImage->File, uOffset, pvBuf, cbToRead, NULL);
411 }
412 else
413 {
414 /** Calculate offset in the real file. */
415 uSector = uOffset / 512;
416 /** One chunk in the file is always one track big. */
417 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
418 uSector = uSector % pImage->PCHSGeometry.cSectors;
419
420 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
421
422 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
423 {
424 rc = VERR_VD_BLOCK_FREE;
425 }
426 else
427 {
428 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
429 rc = RTFileReadAt(pImage->File, uOffsetInFile, pvBuf, cbToRead, NULL);
430 }
431 }
432
433 *pcbActuallyRead = cbToRead;
434
435 LogFlowFunc(("returns %Rrc\n", rc));
436 return rc;
437}
438
439/** @copydoc VBOXHDDBACKEND::pfnWrite */
440static int parallelsWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
441 size_t cbToWrite, size_t *pcbWriteProcess,
442 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
443{
444 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
445 int rc = VINF_SUCCESS;
446 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
447 uint64_t uSector;
448 uint64_t uOffsetInFile;
449 uint32_t iIndexInAllocationTable;
450
451 Assert(pImage);
452 Assert(uOffset % 512 == 0);
453 Assert(cbToWrite % 512 == 0);
454
455 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
456 {
457 rc = RTFileWriteAt(pImage->File, uOffset, pvBuf, cbToWrite, NULL);
458 }
459 else
460 {
461 /** Calculate offset in the real file. */
462 uSector = uOffset / 512;
463 /** One chunk in the file is always one track big. */
464 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
465 uSector = uSector % pImage->PCHSGeometry.cSectors;
466
467 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
468
469 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
470 {
471 /* Allocate new chunk in the file. */
472 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
473 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
474 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
475 pImage->fAllocationBitmapChanged = true;
476 rc = RTFileSetSize(pImage->File, pImage->cbFileCurrent);
477 if (RT_FAILURE(rc))
478 return rc;
479 }
480
481 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
482 rc = RTFileWriteAt(pImage->File, uOffsetInFile, pvBuf, cbToWrite, NULL);
483 }
484
485 *pcbWriteProcess = cbToWrite;
486
487 LogFlowFunc(("returns %Rrc\n", rc));
488 return rc;
489
490}
491
492static int parallelsFlush(void *pBackendData)
493{
494 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
495 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
496 int rc = VINF_SUCCESS;
497
498 Assert(pImage);
499
500 rc = parallelsFlushImage(pImage);
501
502 LogFlowFunc(("returns %Rrc\n", rc));
503 return rc;
504}
505
506/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
507static unsigned parallelsGetVersion(void *pBackendData)
508{
509 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
510 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
511
512 Assert(pImage);
513
514 if (pImage)
515 return PARALLELS_DISK_VERSION;
516 else
517 return 0;
518}
519
520/** @copydoc VBOXHDDBACKEND::pfnGetSize */
521static uint64_t parallelsGetSize(void *pBackendData)
522{
523 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
524 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
525
526 Assert(pImage);
527
528 if (pImage)
529 return pImage->cbSize;
530 else
531 return 0;
532}
533
534/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
535static uint64_t parallelsGetFileSize(void *pBackendData)
536{
537 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
538 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
539 uint64_t cb = 0;
540
541 Assert(pImage);
542
543 if (pImage)
544 {
545 if (pImage->File != NIL_RTFILE)
546 {
547 RTFileGetSize(pImage->File, &cb);
548 }
549 }
550
551 LogFlowFunc(("returns %lld\n", cb));
552 return cb;
553}
554
555/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
556static int parallelsGetPCHSGeometry(void *pBackendData,
557 PPDMMEDIAGEOMETRY pPCHSGeometry)
558{
559 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
560 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
561 int rc;
562
563 Assert(pImage);
564
565 if (pImage)
566 {
567 if (pImage->PCHSGeometry.cCylinders)
568 {
569 *pPCHSGeometry = pImage->PCHSGeometry;
570 rc = VINF_SUCCESS;
571 }
572 else
573 rc = VERR_VD_GEOMETRY_NOT_SET;
574 }
575 else
576 rc = VERR_VD_NOT_OPENED;
577
578 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
579 return rc;
580}
581
582/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
583static int parallelsSetPCHSGeometry(void *pBackendData,
584 PCPDMMEDIAGEOMETRY pPCHSGeometry)
585{
586 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
587 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
588 int rc;
589
590 Assert(pImage);
591
592 if (pImage)
593 {
594 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
595 {
596 rc = VERR_VD_IMAGE_READ_ONLY;
597 goto out;
598 }
599
600 pImage->PCHSGeometry = *pPCHSGeometry;
601 rc = VINF_SUCCESS;
602 }
603 else
604 rc = VERR_VD_NOT_OPENED;
605
606out:
607 LogFlowFunc(("returns %Rrc\n", rc));
608 return rc;
609}
610
611/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
612static int parallelsGetLCHSGeometry(void *pBackendData,
613 PPDMMEDIAGEOMETRY pLCHSGeometry)
614{
615 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
616 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
617 int rc;
618
619 Assert(pImage);
620
621 if (pImage)
622 {
623 if (pImage->LCHSGeometry.cCylinders)
624 {
625 *pLCHSGeometry = pImage->LCHSGeometry;
626 rc = VINF_SUCCESS;
627 }
628 else
629 rc = VERR_VD_GEOMETRY_NOT_SET;
630 }
631 else
632 rc = VERR_VD_NOT_OPENED;
633
634 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
635 return rc;
636}
637
638/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
639static int parallelsSetLCHSGeometry(void *pBackendData,
640 PCPDMMEDIAGEOMETRY pLCHSGeometry)
641{
642 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
643 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
644 int rc;
645
646 Assert(pImage);
647
648 if (pImage)
649 {
650 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
651 {
652 rc = VERR_VD_IMAGE_READ_ONLY;
653 goto out;
654 }
655
656 pImage->LCHSGeometry = *pLCHSGeometry;
657 rc = VINF_SUCCESS;
658 }
659 else
660 rc = VERR_VD_NOT_OPENED;
661
662out:
663 LogFlowFunc(("returns %Rrc\n", rc));
664 return rc;
665}
666
667/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
668static unsigned parallelsGetImageFlags(void *pBackendData)
669{
670 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
671 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
672 unsigned uImageFlags;
673
674 Assert(pImage);
675
676 if (pImage)
677 uImageFlags = pImage->uImageFlags;
678 else
679 uImageFlags = 0;
680
681 LogFlowFunc(("returns %#x\n", uImageFlags));
682 return uImageFlags;
683}
684
685/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
686static unsigned parallelsGetOpenFlags(void *pBackendData)
687{
688 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
689 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
690 unsigned uOpenFlags;
691
692 Assert(pImage);
693
694 if (pImage)
695 uOpenFlags = pImage->uOpenFlags;
696 else
697 uOpenFlags = 0;
698
699 LogFlowFunc(("returns %#x\n", uOpenFlags));
700 return uOpenFlags;
701}
702
703/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
704static int parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
705{
706 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
707 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
708 int rc;
709
710 /* Image must be opened and the new flags must be valid. Just readonly and
711 * info flags are supported. */
712 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
713 {
714 rc = VERR_INVALID_PARAMETER;
715 goto out;
716 }
717
718 /* Implement this operation via reopening the image. */
719 parallelsFreeImage(pImage, false);
720 rc = parallelsOpenImage(pImage, uOpenFlags);
721
722out:
723 LogFlowFunc(("returns %Rrc\n", rc));
724 return rc;
725}
726
727/** @copydoc VBOXHDDBACKEND::pfnGetComment */
728static int parallelsGetComment(void *pBackendData, char *pszComment,
729 size_t cbComment)
730{
731 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
732 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
733 int rc;
734
735 Assert(pImage);
736
737 if (pImage)
738 {
739 rc = VERR_NOT_SUPPORTED;
740 }
741 else
742 rc = VERR_VD_NOT_OPENED;
743
744 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
745 return rc;
746}
747
748/** @copydoc VBOXHDDBACKEND::pfnSetComment */
749static int parallelsSetComment(void *pBackendData, const char *pszComment)
750{
751 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
752 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
753 int rc;
754
755 Assert(pImage);
756
757 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
758 {
759 rc = VERR_VD_IMAGE_READ_ONLY;
760 goto out;
761 }
762
763 if (pImage)
764 rc = VINF_SUCCESS;
765 else
766 rc = VERR_VD_NOT_OPENED;
767
768out:
769 LogFlowFunc(("returns %Rrc\n", rc));
770 return rc;
771}
772
773/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
774static int parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
775{
776 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
777 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
778 int rc;
779
780 Assert(pImage);
781
782 if (pImage)
783 {
784 rc = VERR_NOT_SUPPORTED;
785 }
786 else
787 rc = VERR_VD_NOT_OPENED;
788
789 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
790 return rc;
791}
792
793/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
794static int parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
795{
796 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
797 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
798 int rc;
799
800 LogFlowFunc(("%RTuuid\n", pUuid));
801 Assert(pImage);
802
803 if (pImage)
804 {
805 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
806 {
807 rc = VERR_NOT_SUPPORTED;
808 }
809 else
810 rc = VERR_VD_IMAGE_READ_ONLY;
811 }
812 else
813 rc = VERR_VD_NOT_OPENED;
814
815 LogFlowFunc(("returns %Rrc\n", rc));
816 return rc;
817}
818
819/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
820static int parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
821{
822 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
823 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
824 int rc;
825
826 Assert(pImage);
827
828 if (pImage)
829 {
830 rc = VERR_NOT_SUPPORTED;
831 }
832 else
833 rc = VERR_VD_NOT_OPENED;
834
835 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
836 return rc;
837}
838
839/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
840static int parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
841{
842 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
843 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
844 int rc;
845
846 Assert(pImage);
847
848 if (pImage)
849 {
850 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
851 {
852 rc = VERR_NOT_SUPPORTED;
853 }
854 else
855 rc = VERR_VD_IMAGE_READ_ONLY;
856 }
857 else
858 rc = VERR_VD_NOT_OPENED;
859
860 LogFlowFunc(("returns %Rrc\n", rc));
861 return rc;
862}
863
864/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
865static int parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
866{
867 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
868 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
869 int rc;
870
871 Assert(pImage);
872
873 if (pImage)
874 {
875 rc = VINF_SUCCESS;
876 }
877 else
878 rc = VERR_VD_NOT_OPENED;
879
880 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
881 return rc;
882}
883
884/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
885static int parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
886{
887 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
888 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
889 int rc;
890
891 Assert(pImage);
892
893 if (pImage)
894 {
895 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
896 {
897 rc = VERR_NOT_SUPPORTED;
898 }
899 else
900 rc = VERR_VD_IMAGE_READ_ONLY;
901 }
902 else
903 rc = VERR_VD_NOT_OPENED;
904
905 LogFlowFunc(("returns %Rrc\n", rc));
906 return rc;
907}
908
909/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
910static int parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
911{
912 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
913 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
914 int rc;
915
916 Assert(pImage);
917
918 if (pImage)
919 {
920 rc = VERR_NOT_SUPPORTED;
921 }
922 else
923 rc = VERR_VD_NOT_OPENED;
924
925 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
926 return rc;
927}
928
929/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
930static int parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
931{
932 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
933 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
934 int rc;
935
936 Assert(pImage);
937
938 if (pImage)
939 {
940 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
941 {
942 rc = VERR_NOT_SUPPORTED;
943 }
944 else
945 rc = VERR_VD_IMAGE_READ_ONLY;
946 }
947 else
948 rc = VERR_VD_NOT_OPENED;
949
950 LogFlowFunc(("returns %Rrc\n", rc));
951 return rc;
952}
953
954/** @copydoc VBOXHDDBACKEND::pfnDump */
955static void parallelsDump(void *pBackendData)
956{
957 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
958
959 Assert(pImage);
960 if (pImage)
961 {
962 pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
963 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
964 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
965 }
966}
967
968
969static int parallelsGetTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
970{
971 int rc = VERR_NOT_IMPLEMENTED;
972 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
973 return rc;
974}
975
976static int parallelsGetParentTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
977{
978 int rc = VERR_NOT_IMPLEMENTED;
979 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
980 return rc;
981}
982
983static int parallelsSetParentTimeStamp(void *pvBackendData, PCRTTIMESPEC pTimeStamp)
984{
985 int rc = VERR_NOT_IMPLEMENTED;
986 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
987 return rc;
988}
989
990static int parallelsGetParentFilename(void *pvBackendData, char **ppszParentFilename)
991{
992 int rc = VERR_NOT_IMPLEMENTED;
993 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
994 return rc;
995}
996
997static int parallelsSetParentFilename(void *pvBackendData, const char *pszParentFilename)
998{
999 int rc = VERR_NOT_IMPLEMENTED;
1000 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
1001 return rc;
1002}
1003
1004static bool parallelsIsAsyncIOSupported(void *pvBackendData)
1005{
1006 return false;
1007}
1008
1009static int parallelsAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
1010 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
1011{
1012 return VERR_NOT_SUPPORTED;
1013}
1014
1015static int parallelsAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
1016 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
1017{
1018 return VERR_NOT_SUPPORTED;
1019}
1020
1021VBOXHDDBACKEND g_ParallelsBackend =
1022{
1023 /* pszBackendName */
1024 "Parallels",
1025 /* cbSize */
1026 sizeof(VBOXHDDBACKEND),
1027 /* uBackendCaps */
1028 VD_CAP_FILE | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC,
1029 /* papszFileExtensions */
1030 s_apszParallelsFileExtensions,
1031 /* paConfigInfo */
1032 NULL,
1033 /* hPlugin */
1034 NIL_RTLDRMOD,
1035 /* pfnCheckIfValid */
1036 parallelsCheckIfValid,
1037 /* pfnOpen */
1038 parallelsOpen,
1039 /* pfnCreate */
1040 parallelsCreate,
1041 /* pfnRename */
1042 parallelsRename,
1043 /* pfnClose */
1044 parallelsClose,
1045 /* pfnRead */
1046 parallelsRead,
1047 /* pfnWrite */
1048 parallelsWrite,
1049 /* pfnFlush */
1050 parallelsFlush,
1051 /* pfnGetVersion */
1052 parallelsGetVersion,
1053 /* pfnGetSize */
1054 parallelsGetSize,
1055 /* pfnGetFileSize */
1056 parallelsGetFileSize,
1057 /* pfnGetPCHSGeometry */
1058 parallelsGetPCHSGeometry,
1059 /* pfnSetPCHSGeometry */
1060 parallelsSetPCHSGeometry,
1061 /* pfnGetLCHSGeometry */
1062 parallelsGetLCHSGeometry,
1063 /* pfnSetLCHSGeometry */
1064 parallelsSetLCHSGeometry,
1065 /* pfnGetImageFlags */
1066 parallelsGetImageFlags,
1067 /* pfnGetOpenFlags */
1068 parallelsGetOpenFlags,
1069 /* pfnSetOpenFlags */
1070 parallelsSetOpenFlags,
1071 /* pfnGetComment */
1072 parallelsGetComment,
1073 /* pfnSetComment */
1074 parallelsSetComment,
1075 /* pfnGetUuid */
1076 parallelsGetUuid,
1077 /* pfnSetUuid */
1078 parallelsSetUuid,
1079 /* pfnGetModificationUuid */
1080 parallelsGetModificationUuid,
1081 /* pfnSetModificationUuid */
1082 parallelsSetModificationUuid,
1083 /* pfnGetParentUuid */
1084 parallelsGetParentUuid,
1085 /* pfnSetParentUuid */
1086 parallelsSetParentUuid,
1087 /* pfnGetParentModificationUuid */
1088 parallelsGetParentModificationUuid,
1089 /* pfnSetParentModificationUuid */
1090 parallelsSetParentModificationUuid,
1091 /* pfnDump */
1092 parallelsDump,
1093 /* pfnGetTimeStamp */
1094 parallelsGetTimeStamp,
1095 /* pfnGetParentTimeStamp */
1096 parallelsGetParentTimeStamp,
1097 /* pfnSetParentTimeStamp */
1098 parallelsSetParentTimeStamp,
1099 /* pfnGetParentFilename */
1100 parallelsGetParentFilename,
1101 /* pfnSetParentFilename */
1102 parallelsSetParentFilename,
1103 /* pfnIsAsyncIOSupported */
1104 parallelsIsAsyncIOSupported,
1105 /* pfnAsyncRead */
1106 parallelsAsyncRead,
1107 /* pfnAsyncWrite */
1108 parallelsAsyncWrite,
1109 /* pfnComposeLocation */
1110 genericFileComposeLocation,
1111 /* pfnComposeName */
1112 genericFileComposeName
1113};
1114
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