VirtualBox

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

Last change on this file since 28264 was 27808, checked in by vboxsync, 15 years ago

VBoxHDD: First part of the async I/O support

  • The async I/O interface is not presented to the backend directly anymore but goes through a new interface in VBoxHDD doing the request management
  • Implemented everything to make the old coe work again
  • Async I/O completely disabled for now because it is not working atm (the old code for VMDK was removed)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.0 KB
Line 
1/* $Id: ParallelsHDDCore.cpp 27808 2010-03-29 20:52:56Z vboxsync $ */
2/** @file
3 *
4 * Parallels hdd disk image, core code.
5 */
6
7/*
8 * Copyright (C) 2006-2010 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 <VBox/VBoxHDD-Plugin.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#ifdef VBOX_WITH_NEW_IO_CODE
73 /** Async I/O interface. */
74 PVDINTERFACE pInterfaceIO;
75 /** Async I/O interface callbacks. */
76 PVDINTERFACEIO pInterfaceIOCallbacks;
77#endif
78
79 /** Image file name. */
80 const char *pszFilename;
81#ifndef VBOX_WITH_NEW_IO_CODE
82 /** File descriptor. */
83 RTFILE File;
84#else
85 /** Opaque storage handle. */
86 PVDIOSTORAGE pStorage;
87#endif
88 /** Open flags passed by VBoxHD layer. */
89 unsigned uOpenFlags;
90 /** Image flags defined during creation or determined during open. */
91 unsigned uImageFlags;
92 /** Total size of the image. */
93 uint64_t cbSize;
94 /** Physical geometry of this image. */
95 PDMMEDIAGEOMETRY PCHSGeometry;
96 /** Logical geometry of this image. */
97 PDMMEDIAGEOMETRY LCHSGeometry;
98 /** Pointer to the allocation bitmap. */
99 uint32_t *pAllocationBitmap;
100 /** Entries in the allocation bitmap. */
101 uint64_t cAllocationBitmapEntries;
102 /** Flag whether the allocation bitmap was changed. */
103 bool fAllocationBitmapChanged;
104 /** Current file size. */
105 uint64_t cbFileCurrent;
106} PARALLELSIMAGE, *PPARALLELSIMAGE;
107
108/*******************************************************************************
109* Static Variables *
110*******************************************************************************/
111
112/** NULL-terminated array of supported file extensions. */
113static const char *const s_apszParallelsFileExtensions[] =
114{
115 "hdd",
116 NULL
117};
118
119/***************************************************
120 * Internal functions *
121 **************************************************/
122
123/**
124 * Internal: signal an error to the frontend.
125 */
126DECLINLINE(int) parallelsError(PPARALLELSIMAGE pImage, int rc, RT_SRC_POS_DECL,
127 const char *pszFormat, ...)
128{
129 va_list va;
130 va_start(va, pszFormat);
131 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
132 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
133 pszFormat, va);
134 va_end(va);
135 return rc;
136}
137
138static int parallelsFileOpen(PPARALLELSIMAGE pImage, bool fReadonly, bool fCreate)
139{
140 int rc = VINF_SUCCESS;
141
142 AssertMsg(!(fReadonly && fCreate), ("Image can't be opened readonly while being created\n"));
143
144#ifndef VBOX_WITH_NEW_IO_CODE
145 uint32_t fOpen = fReadonly ? RTFILE_O_READ | RTFILE_O_DENY_NONE
146 : RTFILE_O_READWRITE | RTFILE_O_DENY_WRITE;
147
148 if (fCreate)
149 fOpen |= RTFILE_O_CREATE;
150 else
151 fOpen |= RTFILE_O_OPEN;
152
153 rc = RTFileOpen(&pImage->File, pImage->pszFilename, fOpen);
154#else
155 unsigned uOpenFlags = fReadonly ? VD_INTERFACEASYNCIO_OPEN_FLAGS_READONLY : 0;
156
157 if (fCreate)
158 uOpenFlags |= VD_INTERFACEASYNCIO_OPEN_FLAGS_CREATE;
159
160 rc = pImage->pInterfaceIOCallbacks->pfnOpen(pImage->pInterfaceIO->pvUser,
161 pImage->pszFilename,
162 uOpenFlags,
163 &pImage->pStorage);
164#endif
165
166 return rc;
167}
168
169static int parallelsFileClose(PPARALLELSIMAGE pImage)
170{
171 int rc = VINF_SUCCESS;
172
173#ifndef VBOX_WITH_NEW_IO_CODE
174 if (pImage->File != NIL_RTFILE)
175 rc = RTFileClose(pImage->File);
176
177 pImage->File = NIL_RTFILE;
178#else
179 rc = pImage->pInterfaceIOCallbacks->pfnClose(pImage->pInterfaceIO->pvUser,
180 pImage->pStorage);
181
182 pImage->pStorage = NULL;
183#endif
184
185 return rc;
186}
187
188static int parallelsFileFlushSync(PPARALLELSIMAGE pImage)
189{
190 int rc = VINF_SUCCESS;
191
192#ifndef VBOX_WITH_NEW_IO_CODE
193 rc = RTFileFlush(pImage->File);
194#else
195 rc = pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
196 pImage->pStorage);
197#endif
198
199 return rc;
200}
201
202static int parallelsFileGetSize(PPARALLELSIMAGE pImage, uint64_t *pcbSize)
203{
204 int rc = VINF_SUCCESS;
205
206#ifndef VBOX_WITH_NEW_IO_CODE
207 rc = RTFileGetSize(pImage->File, pcbSize);
208#else
209 rc = pImage->pInterfaceIOCallbacks->pfnGetSize(pImage->pInterfaceIO->pvUser,
210 pImage->pStorage, pcbSize);
211#endif
212
213 return rc;
214
215}
216
217static int parallelsFileSetSize(PPARALLELSIMAGE pImage, uint64_t cbSize)
218{
219 int rc = VINF_SUCCESS;
220
221#ifndef VBOX_WITH_NEW_IO_CODE
222 rc = RTFileSetSize(pImage->File, cbSize);
223#else
224 rc = pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
225 pImage->pStorage,
226 cbSize);
227#endif
228
229 return rc;
230}
231
232
233static int parallelsFileWriteSync(PPARALLELSIMAGE pImage, uint64_t off, const void *pcvBuf, size_t cbWrite, size_t *pcbWritten)
234{
235 int rc = VINF_SUCCESS;
236
237#ifndef VBOX_WITH_NEW_IO_CODE
238 rc = RTFileWriteAt(pImage->File, off, pcvBuf, cbWrite, pcbWritten);
239#else
240 rc = pImage->pInterfaceIOCallbacks->pfnWriteSync(pImage->pInterfaceIO->pvUser,
241 pImage->pStorage,
242 off, cbWrite, pcvBuf,
243 pcbWritten);
244#endif
245
246 return rc;
247}
248
249static int parallelsFileReadSync(PPARALLELSIMAGE pImage, uint64_t off, void *pvBuf, size_t cbRead, size_t *pcbRead)
250{
251 int rc = VINF_SUCCESS;
252
253#ifndef VBOX_WITH_NEW_IO_CODE
254 rc = RTFileReadAt(pImage->File, off, pvBuf, cbRead, pcbRead);
255#else
256 rc = pImage->pInterfaceIOCallbacks->pfnReadSync(pImage->pInterfaceIO->pvUser,
257 pImage->pStorage,
258 off, cbRead, pvBuf,
259 pcbRead);
260#endif
261
262 return rc;
263}
264
265static bool parallelsFileOpened(PPARALLELSIMAGE pImage)
266{
267#ifndef VBOX_WITH_NEW_IO_CODE
268 return pImage->File != NIL_RTFILE;
269#else
270 return pImage->pStorage != NULL;
271#endif
272}
273
274static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
275{
276 int rc = VINF_SUCCESS;
277 ParallelsHeader parallelsHeader;
278
279 /* Try to get error interface. */
280 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
281 if (pImage->pInterfaceError)
282 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
283
284#ifdef VBOX_WITH_NEW_IO_CODE
285 /* Try to get async I/O interface. */
286 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
287 AssertPtr(pImage->pInterfaceIO);
288 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
289 AssertPtr(pImage->pInterfaceIOCallbacks);
290#endif
291
292 rc = parallelsFileOpen(pImage, !!(uOpenFlags & VD_OPEN_FLAGS_READONLY), false);
293 if (RT_FAILURE(rc))
294 goto out;
295
296 rc = parallelsFileGetSize(pImage, &pImage->cbFileCurrent);
297 if (RT_FAILURE(rc))
298 goto out;
299 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
300
301 rc = parallelsFileReadSync(pImage, 0, &parallelsHeader, sizeof(parallelsHeader), NULL);
302 if (RT_FAILURE(rc))
303 goto out;
304
305 if (memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16))
306 {
307 /* Check if the file has hdd as extension. It is a fixed size raw image then. */
308 char *pszExtension = RTPathExt(pImage->pszFilename);
309 if (strcmp(pszExtension, ".hdd"))
310 {
311 rc = VERR_VD_GEN_INVALID_HEADER;
312 goto out;
313 }
314
315 /* This is a fixed size image. */
316 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
317 pImage->cbSize = pImage->cbFileCurrent;
318
319 pImage->PCHSGeometry.cHeads = 16;
320 pImage->PCHSGeometry.cSectors = 63;
321 uint64_t cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
322 pImage->PCHSGeometry.cCylinders = (uint32_t)cCylinders;
323 }
324 else
325 {
326 if (parallelsHeader.uVersion != PARALLELS_DISK_VERSION)
327 {
328 rc = VERR_NOT_SUPPORTED;
329 goto out;
330 }
331
332 if (parallelsHeader.cEntriesInAllocationBitmap > (1 << 30))
333 {
334 rc = VERR_NOT_SUPPORTED;
335 goto out;
336 }
337
338 Log(("cSectors=%u\n", parallelsHeader.cSectors));
339 pImage->cbSize = ((uint64_t)parallelsHeader.cSectors) * 512;
340 pImage->uImageFlags = VD_IMAGE_FLAGS_NONE;
341 pImage->cAllocationBitmapEntries = parallelsHeader.cEntriesInAllocationBitmap;
342 pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ((uint32_t)pImage->cAllocationBitmapEntries * sizeof(uint32_t));
343 if (!pImage->pAllocationBitmap)
344 {
345 rc = VERR_NO_MEMORY;
346 goto out;
347 }
348
349 rc = parallelsFileReadSync(pImage, sizeof(ParallelsHeader),
350 pImage->pAllocationBitmap,
351 pImage->cAllocationBitmapEntries * sizeof(uint32_t),
352 NULL);
353 if (RT_FAILURE(rc))
354 goto out;
355
356 pImage->PCHSGeometry.cCylinders = parallelsHeader.cCylinders;
357 pImage->PCHSGeometry.cHeads = parallelsHeader.cHeads;
358 pImage->PCHSGeometry.cSectors = parallelsHeader.cSectorsPerTrack;
359 }
360
361out:
362 LogFlowFunc(("returns %Rrc\n", rc));
363 return rc;
364}
365
366static int parallelsFlushImage(PPARALLELSIMAGE pImage)
367{
368 LogFlowFunc(("pImage=#%p\n", pImage));
369 int rc = VINF_SUCCESS;
370
371 if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
372 && (pImage->fAllocationBitmapChanged))
373 {
374 pImage->fAllocationBitmapChanged = false;
375 /* Write the allocation bitmap to the file. */
376 rc = parallelsFileWriteSync(pImage, sizeof(ParallelsHeader),
377 pImage->pAllocationBitmap,
378 pImage->cAllocationBitmapEntries * sizeof(uint32_t),
379 NULL);
380 if (RT_FAILURE(rc))
381 return rc;
382 }
383
384 /* Flush file. */
385 rc = parallelsFileFlushSync(pImage);
386
387 LogFlowFunc(("returns %Rrc\n", rc));
388 return rc;
389}
390
391static void parallelsFreeImage(PPARALLELSIMAGE pImage, bool fDelete)
392{
393 (void)parallelsFlushImage(pImage);
394
395 if (pImage->pAllocationBitmap)
396 RTMemFree(pImage->pAllocationBitmap);
397
398 if (parallelsFileOpened(pImage))
399 parallelsFileClose(pImage);
400}
401
402/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
403static int parallelsCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk)
404{
405 RTFILE File;
406 ParallelsHeader parallelsHeader;
407 int rc;
408
409 rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
410 if (RT_FAILURE(rc))
411 return VERR_VD_GEN_INVALID_HEADER;
412
413 rc = RTFileReadAt(File, 0, &parallelsHeader, sizeof(ParallelsHeader), NULL);
414 if (RT_FAILURE(rc))
415 {
416 rc = VERR_VD_GEN_INVALID_HEADER;
417 }
418 else
419 {
420 if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
421 && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
422 rc = VINF_SUCCESS;
423 else
424 {
425 /*
426 * The image may be an fixed size image.
427 * Unfortunately fixed sized parallels images
428 * are just raw files hence no magic header to
429 * check for.
430 * The code succeeds if the file is a multiple
431 * of 512 and if the file extensions is *.hdd
432 */
433 uint64_t cbFile;
434 char *pszExtension;
435
436 rc = RTFileGetSize(File, &cbFile);
437 if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
438 {
439 RTFileClose(File);
440 return VERR_VD_GEN_INVALID_HEADER;
441 }
442
443 pszExtension = RTPathExt(pszFilename);
444 if (!pszExtension || strcmp(pszExtension, ".hdd"))
445 rc = VERR_VD_GEN_INVALID_HEADER;
446 else
447 rc = VINF_SUCCESS;
448 }
449 }
450
451 RTFileClose(File);
452 return rc;
453}
454
455/** @copydoc VBOXHDDBACKEND::pfnOpen */
456static int parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
457 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
458 void **ppBackendData)
459{
460 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
461 int rc;
462 PPARALLELSIMAGE pImage;
463
464 /* Check open flags. All valid flags are supported. */
465 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
466 {
467 rc = VERR_INVALID_PARAMETER;
468 goto out;
469 }
470
471 /* Check remaining arguments. */
472 if ( !VALID_PTR(pszFilename)
473 || !*pszFilename
474 || strchr(pszFilename, '"'))
475 {
476 rc = VERR_INVALID_PARAMETER;
477 goto out;
478 }
479
480 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
481 {
482 rc = VERR_NOT_SUPPORTED;
483 goto out;
484 }
485
486 pImage = (PPARALLELSIMAGE)RTMemAllocZ(sizeof(PARALLELSIMAGE));
487 if (!pImage)
488 {
489 rc = VERR_NO_MEMORY;
490 goto out;
491 }
492
493#ifndef VBOX_WITH_NEW_IO_CODE
494 pImage->File = NIL_RTFILE;
495#else
496 pImage->pStorage = NULL;
497#endif
498 pImage->fAllocationBitmapChanged = false;
499 pImage->pszFilename = pszFilename;
500 pImage->pVDIfsDisk = pVDIfsDisk;
501
502 rc = parallelsOpenImage(pImage, uOpenFlags);
503 if (RT_SUCCESS(rc))
504 *ppBackendData = pImage;
505
506out:
507 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
508 return rc;
509}
510
511/** @copydoc VBOXHDDBACKEND::pfnCreate */
512static int parallelsCreate(const char *pszFilename, uint64_t cbSize,
513 unsigned uImageFlags, const char *pszComment,
514 PCPDMMEDIAGEOMETRY pPCHSGeometry,
515 PCPDMMEDIAGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
516 unsigned uOpenFlags, unsigned uPercentStart,
517 unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
518 PVDINTERFACE pVDIfsImage, PVDINTERFACE pVDIfsOperation,
519 void **ppBackendData)
520{
521 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));
522 return VERR_NOT_IMPLEMENTED;
523}
524
525/** @copydoc VBOXHDDBACKEND::pfnRename */
526static int parallelsRename(void *pBackendData, const char *pszFilename)
527{
528 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
529 return VERR_NOT_IMPLEMENTED;
530}
531
532/** @copydoc VBOXHDDBACKEND::pfnClose */
533static int parallelsClose(void *pBackendData, bool fDelete)
534{
535 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
536 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
537 int rc = VINF_SUCCESS;
538
539 /* Freeing a never allocated image (e.g. because the open failed) is
540 * not signalled as an error. After all nothing bad happens. */
541 if (pImage)
542 parallelsFreeImage(pImage, fDelete);
543
544 LogFlowFunc(("returns %Rrc\n", rc));
545 return rc;
546}
547
548/** @copydoc VBOXHDDBACKEND::pfnRead */
549static int parallelsRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
550 size_t cbToRead, size_t *pcbActuallyRead)
551{
552 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
553 int rc = VINF_SUCCESS;
554 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
555 uint64_t uSector;
556 uint64_t uOffsetInFile;
557 uint32_t iIndexInAllocationTable;
558
559 Assert(pImage);
560 Assert(uOffset % 512 == 0);
561 Assert(cbToRead % 512 == 0);
562
563 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
564 {
565 rc = parallelsFileReadSync(pImage, uOffset,
566 pvBuf, cbToRead, NULL);
567 }
568 else
569 {
570 /** Calculate offset in the real file. */
571 uSector = uOffset / 512;
572 /** One chunk in the file is always one track big. */
573 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
574 uSector = uSector % pImage->PCHSGeometry.cSectors;
575
576 cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
577
578 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
579 {
580 rc = VERR_VD_BLOCK_FREE;
581 }
582 else
583 {
584 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
585 rc = parallelsFileReadSync(pImage, uOffsetInFile,
586 pvBuf, cbToRead, NULL);
587 }
588 }
589
590 *pcbActuallyRead = cbToRead;
591
592 LogFlowFunc(("returns %Rrc\n", rc));
593 return rc;
594}
595
596/** @copydoc VBOXHDDBACKEND::pfnWrite */
597static int parallelsWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
598 size_t cbToWrite, size_t *pcbWriteProcess,
599 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
600{
601 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
602 int rc = VINF_SUCCESS;
603 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
604 uint64_t uSector;
605 uint64_t uOffsetInFile;
606 uint32_t iIndexInAllocationTable;
607
608 Assert(pImage);
609 Assert(uOffset % 512 == 0);
610 Assert(cbToWrite % 512 == 0);
611
612 if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
613 {
614 rc = parallelsFileWriteSync(pImage, uOffset,
615 pvBuf, cbToWrite, NULL);
616 }
617 else
618 {
619 /** Calculate offset in the real file. */
620 uSector = uOffset / 512;
621 /** One chunk in the file is always one track big. */
622 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
623 uSector = uSector % pImage->PCHSGeometry.cSectors;
624
625 cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
626
627 if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
628 {
629 /* Allocate new chunk in the file. */
630 AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
631 pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
632 pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
633 pImage->fAllocationBitmapChanged = true;
634
635 uint8_t *pNewBlock = (uint8_t *)RTMemAllocZ(pImage->PCHSGeometry.cSectors * 512);
636
637 if (!pNewBlock)
638 return VERR_NO_MEMORY;
639
640 uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
641 memcpy(pNewBlock + (uOffset - ((uint64_t)iIndexInAllocationTable * pImage->PCHSGeometry.cSectors * 512)),
642 pvBuf, cbToWrite);
643
644 /*
645 * Write the new block at the current end of the file.
646 */
647 rc = parallelsFileWriteSync(pImage, uOffsetInFile,
648 pNewBlock,
649 pImage->PCHSGeometry.cSectors * 512, NULL);
650
651 RTMemFree(pNewBlock);
652 }
653 else
654 {
655 uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
656 rc = parallelsFileWriteSync(pImage, uOffsetInFile,
657 pvBuf, cbToWrite, NULL);
658 }
659 }
660
661 *pcbWriteProcess = cbToWrite;
662
663 LogFlowFunc(("returns %Rrc\n", rc));
664 return rc;
665
666}
667
668static int parallelsFlush(void *pBackendData)
669{
670 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
671 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
672 int rc = VINF_SUCCESS;
673
674 Assert(pImage);
675
676 rc = parallelsFlushImage(pImage);
677
678 LogFlowFunc(("returns %Rrc\n", rc));
679 return rc;
680}
681
682/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
683static unsigned parallelsGetVersion(void *pBackendData)
684{
685 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
686 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
687
688 Assert(pImage);
689
690 if (pImage)
691 return PARALLELS_DISK_VERSION;
692 else
693 return 0;
694}
695
696/** @copydoc VBOXHDDBACKEND::pfnGetSize */
697static uint64_t parallelsGetSize(void *pBackendData)
698{
699 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
700 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
701
702 Assert(pImage);
703
704 if (pImage)
705 return pImage->cbSize;
706 else
707 return 0;
708}
709
710/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
711static uint64_t parallelsGetFileSize(void *pBackendData)
712{
713 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
714 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
715 uint64_t cb = 0;
716
717 Assert(pImage);
718
719 if (pImage)
720 {
721 if (parallelsFileOpened(pImage))
722 cb = pImage->cbFileCurrent;
723 }
724
725 LogFlowFunc(("returns %lld\n", cb));
726 return cb;
727}
728
729/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
730static int parallelsGetPCHSGeometry(void *pBackendData,
731 PPDMMEDIAGEOMETRY pPCHSGeometry)
732{
733 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
734 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
735 int rc;
736
737 Assert(pImage);
738
739 if (pImage)
740 {
741 if (pImage->PCHSGeometry.cCylinders)
742 {
743 *pPCHSGeometry = pImage->PCHSGeometry;
744 rc = VINF_SUCCESS;
745 }
746 else
747 rc = VERR_VD_GEOMETRY_NOT_SET;
748 }
749 else
750 rc = VERR_VD_NOT_OPENED;
751
752 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
753 return rc;
754}
755
756/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
757static int parallelsSetPCHSGeometry(void *pBackendData,
758 PCPDMMEDIAGEOMETRY pPCHSGeometry)
759{
760 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
761 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
762 int rc;
763
764 Assert(pImage);
765
766 if (pImage)
767 {
768 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
769 {
770 rc = VERR_VD_IMAGE_READ_ONLY;
771 goto out;
772 }
773
774 pImage->PCHSGeometry = *pPCHSGeometry;
775 rc = VINF_SUCCESS;
776 }
777 else
778 rc = VERR_VD_NOT_OPENED;
779
780out:
781 LogFlowFunc(("returns %Rrc\n", rc));
782 return rc;
783}
784
785/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
786static int parallelsGetLCHSGeometry(void *pBackendData,
787 PPDMMEDIAGEOMETRY pLCHSGeometry)
788{
789 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
790 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
791 int rc;
792
793 Assert(pImage);
794
795 if (pImage)
796 {
797 if (pImage->LCHSGeometry.cCylinders)
798 {
799 *pLCHSGeometry = pImage->LCHSGeometry;
800 rc = VINF_SUCCESS;
801 }
802 else
803 rc = VERR_VD_GEOMETRY_NOT_SET;
804 }
805 else
806 rc = VERR_VD_NOT_OPENED;
807
808 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
809 return rc;
810}
811
812/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
813static int parallelsSetLCHSGeometry(void *pBackendData,
814 PCPDMMEDIAGEOMETRY pLCHSGeometry)
815{
816 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
817 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
818 int rc;
819
820 Assert(pImage);
821
822 if (pImage)
823 {
824 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
825 {
826 rc = VERR_VD_IMAGE_READ_ONLY;
827 goto out;
828 }
829
830 pImage->LCHSGeometry = *pLCHSGeometry;
831 rc = VINF_SUCCESS;
832 }
833 else
834 rc = VERR_VD_NOT_OPENED;
835
836out:
837 LogFlowFunc(("returns %Rrc\n", rc));
838 return rc;
839}
840
841/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
842static unsigned parallelsGetImageFlags(void *pBackendData)
843{
844 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
845 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
846 unsigned uImageFlags;
847
848 Assert(pImage);
849
850 if (pImage)
851 uImageFlags = pImage->uImageFlags;
852 else
853 uImageFlags = 0;
854
855 LogFlowFunc(("returns %#x\n", uImageFlags));
856 return uImageFlags;
857}
858
859/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
860static unsigned parallelsGetOpenFlags(void *pBackendData)
861{
862 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
863 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
864 unsigned uOpenFlags;
865
866 Assert(pImage);
867
868 if (pImage)
869 uOpenFlags = pImage->uOpenFlags;
870 else
871 uOpenFlags = 0;
872
873 LogFlowFunc(("returns %#x\n", uOpenFlags));
874 return uOpenFlags;
875}
876
877/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
878static int parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
879{
880 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
881 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
882 int rc;
883
884 /* Image must be opened and the new flags must be valid. Just readonly and
885 * info flags are supported. */
886 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO)))
887 {
888 rc = VERR_INVALID_PARAMETER;
889 goto out;
890 }
891
892 /* Implement this operation via reopening the image. */
893 parallelsFreeImage(pImage, false);
894 rc = parallelsOpenImage(pImage, uOpenFlags);
895
896out:
897 LogFlowFunc(("returns %Rrc\n", rc));
898 return rc;
899}
900
901/** @copydoc VBOXHDDBACKEND::pfnGetComment */
902static int parallelsGetComment(void *pBackendData, char *pszComment,
903 size_t cbComment)
904{
905 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
906 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
907 int rc;
908
909 Assert(pImage);
910
911 if (pImage)
912 {
913 rc = VERR_NOT_SUPPORTED;
914 }
915 else
916 rc = VERR_VD_NOT_OPENED;
917
918 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
919 return rc;
920}
921
922/** @copydoc VBOXHDDBACKEND::pfnSetComment */
923static int parallelsSetComment(void *pBackendData, const char *pszComment)
924{
925 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
926 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
927 int rc;
928
929 Assert(pImage);
930
931 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
932 {
933 rc = VERR_VD_IMAGE_READ_ONLY;
934 goto out;
935 }
936
937 if (pImage)
938 rc = VINF_SUCCESS;
939 else
940 rc = VERR_VD_NOT_OPENED;
941
942out:
943 LogFlowFunc(("returns %Rrc\n", rc));
944 return rc;
945}
946
947/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
948static int parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
949{
950 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
951 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
952 int rc;
953
954 Assert(pImage);
955
956 if (pImage)
957 {
958 rc = VERR_NOT_SUPPORTED;
959 }
960 else
961 rc = VERR_VD_NOT_OPENED;
962
963 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
964 return rc;
965}
966
967/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
968static int parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
969{
970 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
971 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
972 int rc;
973
974 LogFlowFunc(("%RTuuid\n", pUuid));
975 Assert(pImage);
976
977 if (pImage)
978 {
979 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
980 {
981 rc = VERR_NOT_SUPPORTED;
982 }
983 else
984 rc = VERR_VD_IMAGE_READ_ONLY;
985 }
986 else
987 rc = VERR_VD_NOT_OPENED;
988
989 LogFlowFunc(("returns %Rrc\n", rc));
990 return rc;
991}
992
993/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
994static int parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
995{
996 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
997 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
998 int rc;
999
1000 Assert(pImage);
1001
1002 if (pImage)
1003 {
1004 rc = VERR_NOT_SUPPORTED;
1005 }
1006 else
1007 rc = VERR_VD_NOT_OPENED;
1008
1009 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1010 return rc;
1011}
1012
1013/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1014static int parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1015{
1016 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1017 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1018 int rc;
1019
1020 Assert(pImage);
1021
1022 if (pImage)
1023 {
1024 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1025 {
1026 rc = VERR_NOT_SUPPORTED;
1027 }
1028 else
1029 rc = VERR_VD_IMAGE_READ_ONLY;
1030 }
1031 else
1032 rc = VERR_VD_NOT_OPENED;
1033
1034 LogFlowFunc(("returns %Rrc\n", rc));
1035 return rc;
1036}
1037
1038/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1039static int parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
1040{
1041 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1042 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1043 int rc;
1044
1045 Assert(pImage);
1046
1047 if (pImage)
1048 {
1049 rc = VINF_SUCCESS;
1050 }
1051 else
1052 rc = VERR_VD_NOT_OPENED;
1053
1054 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1055 return rc;
1056}
1057
1058/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1059static int parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1060{
1061 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1062 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1063 int rc;
1064
1065 Assert(pImage);
1066
1067 if (pImage)
1068 {
1069 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1070 {
1071 rc = VERR_NOT_SUPPORTED;
1072 }
1073 else
1074 rc = VERR_VD_IMAGE_READ_ONLY;
1075 }
1076 else
1077 rc = VERR_VD_NOT_OPENED;
1078
1079 LogFlowFunc(("returns %Rrc\n", rc));
1080 return rc;
1081}
1082
1083/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1084static int parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1085{
1086 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1087 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1088 int rc;
1089
1090 Assert(pImage);
1091
1092 if (pImage)
1093 {
1094 rc = VERR_NOT_SUPPORTED;
1095 }
1096 else
1097 rc = VERR_VD_NOT_OPENED;
1098
1099 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1100 return rc;
1101}
1102
1103/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1104static int parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1105{
1106 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1107 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1108 int rc;
1109
1110 Assert(pImage);
1111
1112 if (pImage)
1113 {
1114 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1115 {
1116 rc = VERR_NOT_SUPPORTED;
1117 }
1118 else
1119 rc = VERR_VD_IMAGE_READ_ONLY;
1120 }
1121 else
1122 rc = VERR_VD_NOT_OPENED;
1123
1124 LogFlowFunc(("returns %Rrc\n", rc));
1125 return rc;
1126}
1127
1128/** @copydoc VBOXHDDBACKEND::pfnDump */
1129static void parallelsDump(void *pBackendData)
1130{
1131 PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
1132
1133 Assert(pImage);
1134 if (pImage)
1135 {
1136 pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
1137 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1138 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
1139 }
1140}
1141
1142
1143static int parallelsGetTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
1144{
1145 int rc = VERR_NOT_IMPLEMENTED;
1146 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
1147 return rc;
1148}
1149
1150static int parallelsGetParentTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
1151{
1152 int rc = VERR_NOT_IMPLEMENTED;
1153 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
1154 return rc;
1155}
1156
1157static int parallelsSetParentTimeStamp(void *pvBackendData, PCRTTIMESPEC pTimeStamp)
1158{
1159 int rc = VERR_NOT_IMPLEMENTED;
1160 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
1161 return rc;
1162}
1163
1164static int parallelsGetParentFilename(void *pvBackendData, char **ppszParentFilename)
1165{
1166 int rc = VERR_NOT_IMPLEMENTED;
1167 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
1168 return rc;
1169}
1170
1171static int parallelsSetParentFilename(void *pvBackendData, const char *pszParentFilename)
1172{
1173 int rc = VERR_NOT_IMPLEMENTED;
1174 LogFlow(("%s: returned %Rrc\n", __FUNCTION__, rc));
1175 return rc;
1176}
1177
1178static bool parallelsIsAsyncIOSupported(void *pvBackendData)
1179{
1180 return false;
1181}
1182
1183static int parallelsAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
1184 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
1185{
1186 int rc = VERR_NOT_IMPLEMENTED;
1187 LogFlowFunc(("returns %Rrc\n", rc));
1188 return rc;
1189}
1190
1191static int parallelsAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
1192 PVDIOCTX pIoCtx,
1193 size_t *pcbWriteProcess, size_t *pcbPreRead,
1194 size_t *pcbPostRead, unsigned fWrite)
1195{
1196 int rc = VERR_NOT_IMPLEMENTED;
1197 LogFlowFunc(("returns %Rrc\n", rc));
1198 return rc;
1199}
1200
1201static int parallelsAsyncFlush(void *pvBackendData, PVDIOCTX pIoCtx)
1202{
1203 int rc = VERR_NOT_IMPLEMENTED;
1204 LogFlowFunc(("returns %Rrc\n", rc));
1205 return rc;
1206}
1207
1208VBOXHDDBACKEND g_ParallelsBackend =
1209{
1210 /* pszBackendName */
1211 "Parallels",
1212 /* cbSize */
1213 sizeof(VBOXHDDBACKEND),
1214 /* uBackendCaps */
1215 VD_CAP_FILE | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC,
1216 /* papszFileExtensions */
1217 s_apszParallelsFileExtensions,
1218 /* paConfigInfo */
1219 NULL,
1220 /* hPlugin */
1221 NIL_RTLDRMOD,
1222 /* pfnCheckIfValid */
1223 parallelsCheckIfValid,
1224 /* pfnOpen */
1225 parallelsOpen,
1226 /* pfnCreate */
1227 parallelsCreate,
1228 /* pfnRename */
1229 parallelsRename,
1230 /* pfnClose */
1231 parallelsClose,
1232 /* pfnRead */
1233 parallelsRead,
1234 /* pfnWrite */
1235 parallelsWrite,
1236 /* pfnFlush */
1237 parallelsFlush,
1238 /* pfnGetVersion */
1239 parallelsGetVersion,
1240 /* pfnGetSize */
1241 parallelsGetSize,
1242 /* pfnGetFileSize */
1243 parallelsGetFileSize,
1244 /* pfnGetPCHSGeometry */
1245 parallelsGetPCHSGeometry,
1246 /* pfnSetPCHSGeometry */
1247 parallelsSetPCHSGeometry,
1248 /* pfnGetLCHSGeometry */
1249 parallelsGetLCHSGeometry,
1250 /* pfnSetLCHSGeometry */
1251 parallelsSetLCHSGeometry,
1252 /* pfnGetImageFlags */
1253 parallelsGetImageFlags,
1254 /* pfnGetOpenFlags */
1255 parallelsGetOpenFlags,
1256 /* pfnSetOpenFlags */
1257 parallelsSetOpenFlags,
1258 /* pfnGetComment */
1259 parallelsGetComment,
1260 /* pfnSetComment */
1261 parallelsSetComment,
1262 /* pfnGetUuid */
1263 parallelsGetUuid,
1264 /* pfnSetUuid */
1265 parallelsSetUuid,
1266 /* pfnGetModificationUuid */
1267 parallelsGetModificationUuid,
1268 /* pfnSetModificationUuid */
1269 parallelsSetModificationUuid,
1270 /* pfnGetParentUuid */
1271 parallelsGetParentUuid,
1272 /* pfnSetParentUuid */
1273 parallelsSetParentUuid,
1274 /* pfnGetParentModificationUuid */
1275 parallelsGetParentModificationUuid,
1276 /* pfnSetParentModificationUuid */
1277 parallelsSetParentModificationUuid,
1278 /* pfnDump */
1279 parallelsDump,
1280 /* pfnGetTimeStamp */
1281 parallelsGetTimeStamp,
1282 /* pfnGetParentTimeStamp */
1283 parallelsGetParentTimeStamp,
1284 /* pfnSetParentTimeStamp */
1285 parallelsSetParentTimeStamp,
1286 /* pfnGetParentFilename */
1287 parallelsGetParentFilename,
1288 /* pfnSetParentFilename */
1289 parallelsSetParentFilename,
1290 /* pfnIsAsyncIOSupported */
1291 parallelsIsAsyncIOSupported,
1292 /* pfnAsyncRead */
1293 parallelsAsyncRead,
1294 /* pfnAsyncWrite */
1295 parallelsAsyncWrite,
1296 /* pfnAsyncFlush */
1297 parallelsAsyncFlush,
1298 /* pfnComposeLocation */
1299 genericFileComposeLocation,
1300 /* pfnComposeName */
1301 genericFileComposeName,
1302 /* pfnCompact */
1303 NULL
1304};
1305
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette