VirtualBox

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

最後變更 在這個檔案從28620是 28620,由 vboxsync 提交於 15 年 前

VBoxHDD: async I/O updates. Mostly complete except for bug fixes

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

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