VirtualBox

source: vbox/trunk/src/VBox/Storage/RAW.cpp@ 44233

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

Storage: Preparations for the sync/async I/O unification

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 37.1 KB
 
1/* $Id: RAW.cpp 44233 2013-01-04 20:39:56Z vboxsync $ */
2/** @file
3 * RawHDDCore - Raw Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_VD_RAW
22#include <VBox/vd-plugin.h>
23#include <VBox/err.h>
24
25#include <VBox/log.h>
26#include <iprt/assert.h>
27#include <iprt/alloc.h>
28#include <iprt/path.h>
29
30/*******************************************************************************
31* Constants And Macros, Structures and Typedefs *
32*******************************************************************************/
33
34/**
35 * Raw image data structure.
36 */
37typedef struct RAWIMAGE
38{
39 /** Image name. */
40 const char *pszFilename;
41 /** Storage handle. */
42 PVDIOSTORAGE pStorage;
43
44 /** Pointer to the per-disk VD interface list. */
45 PVDINTERFACE pVDIfsDisk;
46 /** Pointer to the per-image VD interface list. */
47 PVDINTERFACE pVDIfsImage;
48 /** Error interface. */
49 PVDINTERFACEERROR pIfError;
50 /** I/O interface. */
51 PVDINTERFACEIOINT pIfIo;
52
53 /** Open flags passed by VBoxHD layer. */
54 unsigned uOpenFlags;
55 /** Image flags defined during creation or determined during open. */
56 unsigned uImageFlags;
57 /** Total size of the image. */
58 uint64_t cbSize;
59 /** Position in the image (only truly used for sequential access). */
60 uint64_t offAccess;
61 /** Flag if this is a newly created image. */
62 bool fCreate;
63 /** Physical geometry of this image. */
64 VDGEOMETRY PCHSGeometry;
65 /** Logical geometry of this image. */
66 VDGEOMETRY LCHSGeometry;
67
68} RAWIMAGE, *PRAWIMAGE;
69
70
71/** Size of write operations when filling an image with zeroes. */
72#define RAW_FILL_SIZE (128 * _1K)
73
74/** The maximum reasonable size of a floppy image (big format 2.88MB medium). */
75#define RAW_MAX_FLOPPY_IMG_SIZE (512 * 82 * 48 * 2)
76
77/*******************************************************************************
78* Static Variables *
79*******************************************************************************/
80
81/** NULL-terminated array of supported file extensions. */
82static const VDFILEEXTENSION s_aRawFileExtensions[] =
83{
84 {"iso", VDTYPE_DVD},
85 {"cdr", VDTYPE_DVD},
86 {"img", VDTYPE_FLOPPY},
87 {"ima", VDTYPE_FLOPPY},
88 {"dsk", VDTYPE_FLOPPY},
89 {"vfd", VDTYPE_FLOPPY},
90 {NULL, VDTYPE_INVALID}
91};
92
93/*******************************************************************************
94* Internal Functions *
95*******************************************************************************/
96
97/**
98 * Internal. Flush image data to disk.
99 */
100static int rawFlushImage(PRAWIMAGE pImage)
101{
102 int rc = VINF_SUCCESS;
103
104 if ( pImage->pStorage
105 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
106 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
107
108 return rc;
109}
110
111/**
112 * Internal. Free all allocated space for representing an image except pImage,
113 * and optionally delete the image from disk.
114 */
115static int rawFreeImage(PRAWIMAGE pImage, bool fDelete)
116{
117 int rc = VINF_SUCCESS;
118
119 /* Freeing a never allocated image (e.g. because the open failed) is
120 * not signalled as an error. After all nothing bad happens. */
121 if (pImage)
122 {
123 if (pImage->pStorage)
124 {
125 /* No point updating the file that is deleted anyway. */
126 if (!fDelete)
127 {
128 /* For newly created images in sequential mode fill it to
129 * the nominal size. */
130 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
131 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
132 && pImage->fCreate)
133 {
134 /* Fill rest of image with zeroes, a must for sequential
135 * images to reach the nominal size. */
136 uint64_t uOff;
137 void *pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
138 if (!pvBuf)
139 goto out;
140
141 uOff = pImage->offAccess;
142 /* Write data to all image blocks. */
143 while (uOff < pImage->cbSize)
144 {
145 unsigned cbChunk = (unsigned)RT_MIN(pImage->cbSize,
146 RAW_FILL_SIZE);
147
148 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
149 uOff, pvBuf, cbChunk);
150 if (RT_FAILURE(rc))
151 goto out;
152
153 uOff += cbChunk;
154 }
155out:
156 if (pvBuf)
157 RTMemTmpFree(pvBuf);
158 }
159 rawFlushImage(pImage);
160 }
161
162 vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
163 pImage->pStorage = NULL;
164 }
165
166 if (fDelete && pImage->pszFilename)
167 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
168 }
169
170 LogFlowFunc(("returns %Rrc\n", rc));
171 return rc;
172}
173
174/**
175 * Internal: Open an image, constructing all necessary data structures.
176 */
177static int rawOpenImage(PRAWIMAGE pImage, unsigned uOpenFlags)
178{
179 int rc;
180
181 pImage->uOpenFlags = uOpenFlags;
182 pImage->fCreate = false;
183
184 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
185 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
186 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
187
188 /*
189 * Open the image.
190 */
191 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
192 VDOpenFlagsToFileOpenFlags(uOpenFlags,
193 false /* fCreate */),
194 &pImage->pStorage);
195 if (RT_FAILURE(rc))
196 {
197 /* Do NOT signal an appropriate error here, as the VD layer has the
198 * choice of retrying the open if it failed. */
199 goto out;
200 }
201
202 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbSize);
203 if (RT_FAILURE(rc))
204 goto out;
205 if (pImage->cbSize % 512)
206 {
207 rc = VERR_VD_RAW_INVALID_HEADER;
208 goto out;
209 }
210 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
211
212out:
213 if (RT_FAILURE(rc))
214 rawFreeImage(pImage, false);
215 return rc;
216}
217
218/**
219 * Internal: Create a raw image.
220 */
221static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize,
222 unsigned uImageFlags, const char *pszComment,
223 PCVDGEOMETRY pPCHSGeometry,
224 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
225 PFNVDPROGRESS pfnProgress, void *pvUser,
226 unsigned uPercentStart, unsigned uPercentSpan)
227{
228 int rc;
229 RTFOFF cbFree = 0;
230 uint64_t uOff;
231 void *pvBuf = NULL;
232 int32_t fOpen;
233
234 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
235
236 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
237
238 pImage->uImageFlags = uImageFlags;
239 pImage->fCreate = true;
240 pImage->PCHSGeometry = *pPCHSGeometry;
241 pImage->LCHSGeometry = *pLCHSGeometry;
242
243 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
244 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
245 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
246
247 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
248 {
249 rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
250 goto out;
251 }
252
253 /* Create image file. */
254 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
255 if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
256 fOpen &= ~RTFILE_O_READ;
257 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
258 if (RT_FAILURE(rc))
259 {
260 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
261 goto out;
262 }
263
264 if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
265 {
266 /* Check the free space on the disk and leave early if there is not
267 * sufficient space available. */
268 rc = vdIfIoIntFileGetFreeSpace(pImage->pIfIo, pImage->pszFilename, &cbFree);
269 if (RT_SUCCESS(rc) /* ignore errors */ && ((uint64_t)cbFree < cbSize))
270 {
271 rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
272 goto out;
273 }
274
275 /* Allocate & commit whole file if fixed image, it must be more
276 * effective than expanding file by write operations. */
277 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbSize);
278 if (RT_FAILURE(rc))
279 {
280 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: setting image size failed for '%s'"), pImage->pszFilename);
281 goto out;
282 }
283
284 /* Fill image with zeroes. We do this for every fixed-size image since
285 * on some systems (for example Windows Vista), it takes ages to write
286 * a block near the end of a sparse file and the guest could complain
287 * about an ATA timeout. */
288 pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
289 if (!pvBuf)
290 {
291 rc = VERR_NO_MEMORY;
292 goto out;
293 }
294
295 uOff = 0;
296 /* Write data to all image blocks. */
297 while (uOff < cbSize)
298 {
299 unsigned cbChunk = (unsigned)RT_MIN(cbSize, RAW_FILL_SIZE);
300
301 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOff,
302 pvBuf, cbChunk);
303 if (RT_FAILURE(rc))
304 {
305 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: writing block failed for '%s'"), pImage->pszFilename);
306 goto out;
307 }
308
309 uOff += cbChunk;
310
311 if (pfnProgress)
312 {
313 rc = pfnProgress(pvUser,
314 uPercentStart + uOff * uPercentSpan * 98 / (cbSize * 100));
315 if (RT_FAILURE(rc))
316 goto out;
317 }
318 }
319 }
320
321 if (RT_SUCCESS(rc) && pfnProgress)
322 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
323
324 pImage->cbSize = cbSize;
325
326 rc = rawFlushImage(pImage);
327
328out:
329 if (pvBuf)
330 RTMemTmpFree(pvBuf);
331
332 if (RT_SUCCESS(rc) && pfnProgress)
333 pfnProgress(pvUser, uPercentStart + uPercentSpan);
334
335 if (RT_FAILURE(rc))
336 rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
337 return rc;
338}
339
340
341/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
342static int rawCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
343 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
344{
345 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
346 PVDIOSTORAGE pStorage = NULL;
347 uint64_t cbFile;
348 int rc = VINF_SUCCESS;
349 char *pszExtension = NULL;
350
351 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
352 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
353
354 if ( !VALID_PTR(pszFilename)
355 || !*pszFilename)
356 {
357 rc = VERR_INVALID_PARAMETER;
358 goto out;
359 }
360
361 pszExtension = RTPathExt(pszFilename);
362
363 /*
364 * Open the file and read the footer.
365 */
366 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
367 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
368 false /* fCreate */),
369 &pStorage);
370 if (RT_SUCCESS(rc))
371 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
372
373 /* Try to guess the image type based on the extension. */
374 if ( RT_SUCCESS(rc)
375 && pszExtension)
376 {
377 if ( !RTStrICmp(pszExtension, ".iso")
378 || !RTStrICmp(pszExtension, ".cdr")) /* DVD images. */
379 {
380 /* Note that there are ISO images smaller than 1 MB; it is impossible to distinguish
381 * between raw floppy and CD images based on their size (and cannot be reliably done
382 * based on contents, either).
383 */
384 if (cbFile > 32768 && !(cbFile % 2048))
385 {
386 *penmType = VDTYPE_DVD;
387 rc = VINF_SUCCESS;
388 }
389 else
390 rc = VERR_VD_RAW_INVALID_HEADER;
391 }
392 else if ( !RTStrICmp(pszExtension, ".img")
393 || !RTStrICmp(pszExtension, ".ima")
394 || !RTStrICmp(pszExtension, ".dsk")
395 || !RTStrICmp(pszExtension, ".vfd")) /* Floppy images */
396 {
397 if (!(cbFile % 512) && cbFile <= RAW_MAX_FLOPPY_IMG_SIZE)
398 {
399 *penmType = VDTYPE_FLOPPY;
400 rc = VINF_SUCCESS;
401 }
402 else
403 rc = VERR_VD_RAW_INVALID_HEADER;
404 }
405 else
406 rc = VERR_VD_RAW_INVALID_HEADER;
407 }
408 else
409 rc = VERR_VD_RAW_INVALID_HEADER;
410
411 if (pStorage)
412 vdIfIoIntFileClose(pIfIo, pStorage);
413
414out:
415 LogFlowFunc(("returns %Rrc\n", rc));
416 return rc;
417}
418
419/** @copydoc VBOXHDDBACKEND::pfnOpen */
420static int rawOpen(const char *pszFilename, unsigned uOpenFlags,
421 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
422 VDTYPE enmType, void **ppBackendData)
423{
424 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
425 int rc;
426 PRAWIMAGE pImage;
427
428 /* Check open flags. All valid flags are supported. */
429 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
430 {
431 rc = VERR_INVALID_PARAMETER;
432 goto out;
433 }
434
435 /* Check remaining arguments. */
436 if ( !VALID_PTR(pszFilename)
437 || !*pszFilename)
438 {
439 rc = VERR_INVALID_PARAMETER;
440 goto out;
441 }
442
443
444 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
445 if (!pImage)
446 {
447 rc = VERR_NO_MEMORY;
448 goto out;
449 }
450 pImage->pszFilename = pszFilename;
451 pImage->pStorage = NULL;
452 pImage->pVDIfsDisk = pVDIfsDisk;
453 pImage->pVDIfsImage = pVDIfsImage;
454
455 rc = rawOpenImage(pImage, uOpenFlags);
456 if (RT_SUCCESS(rc))
457 *ppBackendData = pImage;
458 else
459 RTMemFree(pImage);
460
461out:
462 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
463 return rc;
464}
465
466/** @copydoc VBOXHDDBACKEND::pfnCreate */
467static int rawCreate(const char *pszFilename, uint64_t cbSize,
468 unsigned uImageFlags, const char *pszComment,
469 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
470 PCRTUUID pUuid, unsigned uOpenFlags,
471 unsigned uPercentStart, unsigned uPercentSpan,
472 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
473 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
474{
475 LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p ppBackendData=%#p", pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
476 int rc;
477 PRAWIMAGE pImage;
478
479 PFNVDPROGRESS pfnProgress = NULL;
480 void *pvUser = NULL;
481 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
482 if (pIfProgress)
483 {
484 pfnProgress = pIfProgress->pfnProgress;
485 pvUser = pIfProgress->Core.pvUser;
486 }
487
488 /* Check open flags. All valid flags are supported. */
489 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
490 {
491 rc = VERR_INVALID_PARAMETER;
492 goto out;
493 }
494
495 /* Check remaining arguments. */
496 if ( !VALID_PTR(pszFilename)
497 || !*pszFilename
498 || !VALID_PTR(pPCHSGeometry)
499 || !VALID_PTR(pLCHSGeometry))
500 {
501 rc = VERR_INVALID_PARAMETER;
502 goto out;
503 }
504
505 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
506 if (!pImage)
507 {
508 rc = VERR_NO_MEMORY;
509 goto out;
510 }
511 pImage->pszFilename = pszFilename;
512 pImage->pStorage = NULL;
513 pImage->pVDIfsDisk = pVDIfsDisk;
514 pImage->pVDIfsImage = pVDIfsImage;
515
516 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
517 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
518 pfnProgress, pvUser, uPercentStart, uPercentSpan);
519 if (RT_SUCCESS(rc))
520 {
521 /* So far the image is opened in read/write mode. Make sure the
522 * image is opened in read-only mode if the caller requested that. */
523 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
524 {
525 rawFreeImage(pImage, false);
526 rc = rawOpenImage(pImage, uOpenFlags);
527 if (RT_FAILURE(rc))
528 {
529 RTMemFree(pImage);
530 goto out;
531 }
532 }
533 *ppBackendData = pImage;
534 }
535 else
536 RTMemFree(pImage);
537
538out:
539 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
540 return rc;
541}
542
543/** @copydoc VBOXHDDBACKEND::pfnRename */
544static int rawRename(void *pBackendData, const char *pszFilename)
545{
546 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
547 int rc = VINF_SUCCESS;
548 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
549
550 /* Check arguments. */
551 if ( !pImage
552 || !pszFilename
553 || !*pszFilename)
554 {
555 rc = VERR_INVALID_PARAMETER;
556 goto out;
557 }
558
559 /* Close the image. */
560 rc = rawFreeImage(pImage, false);
561 if (RT_FAILURE(rc))
562 goto out;
563
564 /* Rename the file. */
565 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
566 if (RT_FAILURE(rc))
567 {
568 /* The move failed, try to reopen the original image. */
569 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
570 if (RT_FAILURE(rc2))
571 rc = rc2;
572
573 goto out;
574 }
575
576 /* Update pImage with the new information. */
577 pImage->pszFilename = pszFilename;
578
579 /* Open the old image with new name. */
580 rc = rawOpenImage(pImage, pImage->uOpenFlags);
581 if (RT_FAILURE(rc))
582 goto out;
583
584out:
585 LogFlowFunc(("returns %Rrc\n", rc));
586 return rc;
587}
588
589/** @copydoc VBOXHDDBACKEND::pfnClose */
590static int rawClose(void *pBackendData, bool fDelete)
591{
592 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
593 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
594 int rc;
595
596 rc = rawFreeImage(pImage, fDelete);
597 RTMemFree(pImage);
598
599 LogFlowFunc(("returns %Rrc\n", rc));
600 return rc;
601}
602
603/** @copydoc VBOXHDDBACKEND::pfnRead */
604static int rawRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
605 size_t cbToRead, size_t *pcbActuallyRead)
606{
607 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
608 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
609 int rc;
610
611 AssertPtr(pImage);
612 Assert(uOffset % 512 == 0);
613 Assert(cbToRead % 512 == 0);
614
615 if ( uOffset + cbToRead > pImage->cbSize
616 || cbToRead == 0)
617 {
618 rc = VERR_INVALID_PARAMETER;
619 goto out;
620 }
621
622 /* For sequential access do not allow to go back. */
623 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
624 && uOffset < pImage->offAccess)
625 {
626 rc = VERR_INVALID_PARAMETER;
627 goto out;
628 }
629
630 rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf,
631 cbToRead);
632 pImage->offAccess = uOffset + cbToRead;
633 if (pcbActuallyRead)
634 *pcbActuallyRead = cbToRead;
635
636out:
637 LogFlowFunc(("returns %Rrc\n", rc));
638 return rc;
639}
640
641/** @copydoc VBOXHDDBACKEND::pfnWrite */
642static int rawWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
643 size_t cbToWrite, size_t *pcbWriteProcess,
644 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
645{
646 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
647 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
648 int rc;
649
650 AssertPtr(pImage);
651 Assert(uOffset % 512 == 0);
652 Assert(cbToWrite % 512 == 0);
653
654 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
655 {
656 rc = VERR_VD_IMAGE_READ_ONLY;
657 goto out;
658 }
659
660 if ( uOffset + cbToWrite > pImage->cbSize
661 || cbToWrite == 0)
662 {
663 rc = VERR_INVALID_PARAMETER;
664 goto out;
665 }
666
667 /* For sequential access do not allow to go back. */
668 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
669 && uOffset < pImage->offAccess)
670 {
671 rc = VERR_INVALID_PARAMETER;
672 goto out;
673 }
674
675 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf,
676 cbToWrite);
677 pImage->offAccess = uOffset + cbToWrite;
678 if (pcbWriteProcess)
679 *pcbWriteProcess = cbToWrite;
680
681out:
682 LogFlowFunc(("returns %Rrc\n", rc));
683 return rc;
684}
685
686/** @copydoc VBOXHDDBACKEND::pfnFlush */
687static int rawFlush(void *pBackendData)
688{
689 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
690 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
691 int rc;
692
693 rc = rawFlushImage(pImage);
694 LogFlowFunc(("returns %Rrc\n", rc));
695 return rc;
696}
697
698/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
699static unsigned rawGetVersion(void *pBackendData)
700{
701 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
702 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
703
704 AssertPtr(pImage);
705
706 if (pImage)
707 return 1;
708 else
709 return 0;
710}
711
712/** @copydoc VBOXHDDBACKEND::pfnGetSize */
713static uint64_t rawGetSize(void *pBackendData)
714{
715 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
716 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
717 uint64_t cb = 0;
718
719 AssertPtr(pImage);
720
721 if (pImage && pImage->pStorage)
722 cb = pImage->cbSize;
723
724 LogFlowFunc(("returns %llu\n", cb));
725 return cb;
726}
727
728/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
729static uint64_t rawGetFileSize(void *pBackendData)
730{
731 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
732 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
733 uint64_t cb = 0;
734
735 AssertPtr(pImage);
736
737 if (pImage)
738 {
739 uint64_t cbFile;
740 if (pImage->pStorage)
741 {
742 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
743 if (RT_SUCCESS(rc))
744 cb += cbFile;
745 }
746 }
747
748 LogFlowFunc(("returns %lld\n", cb));
749 return cb;
750}
751
752/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
753static int rawGetPCHSGeometry(void *pBackendData,
754 PVDGEOMETRY pPCHSGeometry)
755{
756 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
757 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
758 int rc;
759
760 AssertPtr(pImage);
761
762 if (pImage)
763 {
764 if (pImage->PCHSGeometry.cCylinders)
765 {
766 *pPCHSGeometry = pImage->PCHSGeometry;
767 rc = VINF_SUCCESS;
768 }
769 else
770 rc = VERR_VD_GEOMETRY_NOT_SET;
771 }
772 else
773 rc = VERR_VD_NOT_OPENED;
774
775 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
776 return rc;
777}
778
779/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
780static int rawSetPCHSGeometry(void *pBackendData,
781 PCVDGEOMETRY pPCHSGeometry)
782{
783 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
784 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
785 int rc;
786
787 AssertPtr(pImage);
788
789 if (pImage)
790 {
791 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
792 {
793 rc = VERR_VD_IMAGE_READ_ONLY;
794 goto out;
795 }
796
797 pImage->PCHSGeometry = *pPCHSGeometry;
798 rc = VINF_SUCCESS;
799 }
800 else
801 rc = VERR_VD_NOT_OPENED;
802
803out:
804 LogFlowFunc(("returns %Rrc\n", rc));
805 return rc;
806}
807
808/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
809static int rawGetLCHSGeometry(void *pBackendData,
810 PVDGEOMETRY pLCHSGeometry)
811{
812 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
813 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
814 int rc;
815
816 AssertPtr(pImage);
817
818 if (pImage)
819 {
820 if (pImage->LCHSGeometry.cCylinders)
821 {
822 *pLCHSGeometry = pImage->LCHSGeometry;
823 rc = VINF_SUCCESS;
824 }
825 else
826 rc = VERR_VD_GEOMETRY_NOT_SET;
827 }
828 else
829 rc = VERR_VD_NOT_OPENED;
830
831 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
832 return rc;
833}
834
835/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
836static int rawSetLCHSGeometry(void *pBackendData,
837 PCVDGEOMETRY pLCHSGeometry)
838{
839 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
840 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
841 int rc;
842
843 AssertPtr(pImage);
844
845 if (pImage)
846 {
847 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
848 {
849 rc = VERR_VD_IMAGE_READ_ONLY;
850 goto out;
851 }
852
853 pImage->LCHSGeometry = *pLCHSGeometry;
854 rc = VINF_SUCCESS;
855 }
856 else
857 rc = VERR_VD_NOT_OPENED;
858
859out:
860 LogFlowFunc(("returns %Rrc\n", rc));
861 return rc;
862}
863
864/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
865static unsigned rawGetImageFlags(void *pBackendData)
866{
867 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
868 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
869 unsigned uImageFlags;
870
871 AssertPtr(pImage);
872
873 if (pImage)
874 uImageFlags = pImage->uImageFlags;
875 else
876 uImageFlags = 0;
877
878 LogFlowFunc(("returns %#x\n", uImageFlags));
879 return uImageFlags;
880}
881
882/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
883static unsigned rawGetOpenFlags(void *pBackendData)
884{
885 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
886 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
887 unsigned uOpenFlags;
888
889 AssertPtr(pImage);
890
891 if (pImage)
892 uOpenFlags = pImage->uOpenFlags;
893 else
894 uOpenFlags = 0;
895
896 LogFlowFunc(("returns %#x\n", uOpenFlags));
897 return uOpenFlags;
898}
899
900/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
901static int rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
902{
903 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
904 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
905 int rc;
906
907 /* Image must be opened and the new flags must be valid. */
908 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
909 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
910 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
911 {
912 rc = VERR_INVALID_PARAMETER;
913 goto out;
914 }
915
916 /* Implement this operation via reopening the image. */
917 rc = rawFreeImage(pImage, false);
918 if (RT_FAILURE(rc))
919 goto out;
920 rc = rawOpenImage(pImage, uOpenFlags);
921
922out:
923 LogFlowFunc(("returns %Rrc\n", rc));
924 return rc;
925}
926
927/** @copydoc VBOXHDDBACKEND::pfnGetComment */
928static int rawGetComment(void *pBackendData, char *pszComment,
929 size_t cbComment)
930{
931 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
932 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
933 int rc;
934
935 AssertPtr(pImage);
936
937 if (pImage)
938 rc = VERR_NOT_SUPPORTED;
939 else
940 rc = VERR_VD_NOT_OPENED;
941
942 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
943 return rc;
944}
945
946/** @copydoc VBOXHDDBACKEND::pfnSetComment */
947static int rawSetComment(void *pBackendData, const char *pszComment)
948{
949 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
950 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
951 int rc;
952
953 AssertPtr(pImage);
954
955 if (pImage)
956 {
957 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
958 rc = VERR_VD_IMAGE_READ_ONLY;
959 else
960 rc = VERR_NOT_SUPPORTED;
961 }
962 else
963 rc = VERR_VD_NOT_OPENED;
964
965 LogFlowFunc(("returns %Rrc\n", rc));
966 return rc;
967}
968
969/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
970static int rawGetUuid(void *pBackendData, PRTUUID pUuid)
971{
972 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
973 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
974 int rc;
975
976 AssertPtr(pImage);
977
978 if (pImage)
979 rc = VERR_NOT_SUPPORTED;
980 else
981 rc = VERR_VD_NOT_OPENED;
982
983 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
984 return rc;
985}
986
987/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
988static int rawSetUuid(void *pBackendData, PCRTUUID pUuid)
989{
990 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
991 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
992 int rc;
993
994 LogFlowFunc(("%RTuuid\n", pUuid));
995 AssertPtr(pImage);
996
997 if (pImage)
998 {
999 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1000 rc = VERR_NOT_SUPPORTED;
1001 else
1002 rc = VERR_VD_IMAGE_READ_ONLY;
1003 }
1004 else
1005 rc = VERR_VD_NOT_OPENED;
1006
1007 LogFlowFunc(("returns %Rrc\n", rc));
1008 return rc;
1009}
1010
1011/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1012static int rawGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1013{
1014 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1015 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1016 int rc;
1017
1018 AssertPtr(pImage);
1019
1020 if (pImage)
1021 rc = VERR_NOT_SUPPORTED;
1022 else
1023 rc = VERR_VD_NOT_OPENED;
1024
1025 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1026 return rc;
1027}
1028
1029/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1030static int rawSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1031{
1032 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1033 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1034 int rc;
1035
1036 AssertPtr(pImage);
1037
1038 if (pImage)
1039 {
1040 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1041 rc = VERR_NOT_SUPPORTED;
1042 else
1043 rc = VERR_VD_IMAGE_READ_ONLY;
1044 }
1045 else
1046 rc = VERR_VD_NOT_OPENED;
1047
1048 LogFlowFunc(("returns %Rrc\n", rc));
1049 return rc;
1050}
1051
1052/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1053static int rawGetParentUuid(void *pBackendData, PRTUUID pUuid)
1054{
1055 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1056 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1057 int rc;
1058
1059 AssertPtr(pImage);
1060
1061 if (pImage)
1062 rc = VERR_NOT_SUPPORTED;
1063 else
1064 rc = VERR_VD_NOT_OPENED;
1065
1066 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1067 return rc;
1068}
1069
1070/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1071static int rawSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1072{
1073 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1074 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1075 int rc;
1076
1077 AssertPtr(pImage);
1078
1079 if (pImage)
1080 {
1081 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1082 rc = VERR_NOT_SUPPORTED;
1083 else
1084 rc = VERR_VD_IMAGE_READ_ONLY;
1085 }
1086 else
1087 rc = VERR_VD_NOT_OPENED;
1088
1089 LogFlowFunc(("returns %Rrc\n", rc));
1090 return rc;
1091}
1092
1093/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1094static int rawGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1095{
1096 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1097 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1098 int rc;
1099
1100 AssertPtr(pImage);
1101
1102 if (pImage)
1103 rc = VERR_NOT_SUPPORTED;
1104 else
1105 rc = VERR_VD_NOT_OPENED;
1106
1107 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1108 return rc;
1109}
1110
1111/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1112static int rawSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1113{
1114 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1115 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1116 int rc;
1117
1118 AssertPtr(pImage);
1119
1120 if (pImage)
1121 {
1122 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1123 rc = VERR_NOT_SUPPORTED;
1124 else
1125 rc = VERR_VD_IMAGE_READ_ONLY;
1126 }
1127 else
1128 rc = VERR_VD_NOT_OPENED;
1129
1130 LogFlowFunc(("returns %Rrc\n", rc));
1131 return rc;
1132}
1133
1134/** @copydoc VBOXHDDBACKEND::pfnDump */
1135static void rawDump(void *pBackendData)
1136{
1137 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1138
1139 AssertPtr(pImage);
1140 if (pImage)
1141 {
1142 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
1143 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1144 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
1145 pImage->cbSize / 512);
1146 }
1147}
1148
1149/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
1150static int rawAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
1151 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
1152{
1153 int rc = VINF_SUCCESS;
1154 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1155
1156 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
1157 pIoCtx, cbRead);
1158 if (RT_SUCCESS(rc))
1159 *pcbActuallyRead = cbRead;
1160
1161 return rc;
1162}
1163
1164/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
1165static int rawAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
1166 PVDIOCTX pIoCtx,
1167 size_t *pcbWriteProcess, size_t *pcbPreRead,
1168 size_t *pcbPostRead, unsigned fWrite)
1169{
1170 int rc = VINF_SUCCESS;
1171 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1172
1173 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
1174 pIoCtx, cbWrite, NULL, NULL);
1175 if (RT_SUCCESS(rc))
1176 {
1177 *pcbWriteProcess = cbWrite;
1178 *pcbPostRead = 0;
1179 *pcbPreRead = 0;
1180 }
1181
1182 return rc;
1183}
1184
1185/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
1186static int rawAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
1187{
1188 int rc = VINF_SUCCESS;
1189 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1190
1191 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1192 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
1193 NULL, NULL);
1194
1195 return rc;
1196}
1197
1198
1199VBOXHDDBACKEND g_RawBackend =
1200{
1201 /* pszBackendName */
1202 "RAW",
1203 /* cbSize */
1204 sizeof(VBOXHDDBACKEND),
1205 /* uBackendCaps */
1206 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1207 /* paFileExtensions */
1208 s_aRawFileExtensions,
1209 /* paConfigInfo */
1210 NULL,
1211 /* hPlugin */
1212 NIL_RTLDRMOD,
1213 /* pfnCheckIfValid */
1214 rawCheckIfValid,
1215 /* pfnOpen */
1216 rawOpen,
1217 /* pfnCreate */
1218 rawCreate,
1219 /* pfnRename */
1220 rawRename,
1221 /* pfnClose */
1222 rawClose,
1223 /* pfnRead */
1224 rawRead,
1225 /* pfnWrite */
1226 rawWrite,
1227 /* pfnFlush */
1228 rawFlush,
1229 /* pfnGetVersion */
1230 rawGetVersion,
1231 /* pfnGetSize */
1232 rawGetSize,
1233 /* pfnGetFileSize */
1234 rawGetFileSize,
1235 /* pfnGetPCHSGeometry */
1236 rawGetPCHSGeometry,
1237 /* pfnSetPCHSGeometry */
1238 rawSetPCHSGeometry,
1239 /* pfnGetLCHSGeometry */
1240 rawGetLCHSGeometry,
1241 /* pfnSetLCHSGeometry */
1242 rawSetLCHSGeometry,
1243 /* pfnGetImageFlags */
1244 rawGetImageFlags,
1245 /* pfnGetOpenFlags */
1246 rawGetOpenFlags,
1247 /* pfnSetOpenFlags */
1248 rawSetOpenFlags,
1249 /* pfnGetComment */
1250 rawGetComment,
1251 /* pfnSetComment */
1252 rawSetComment,
1253 /* pfnGetUuid */
1254 rawGetUuid,
1255 /* pfnSetUuid */
1256 rawSetUuid,
1257 /* pfnGetModificationUuid */
1258 rawGetModificationUuid,
1259 /* pfnSetModificationUuid */
1260 rawSetModificationUuid,
1261 /* pfnGetParentUuid */
1262 rawGetParentUuid,
1263 /* pfnSetParentUuid */
1264 rawSetParentUuid,
1265 /* pfnGetParentModificationUuid */
1266 rawGetParentModificationUuid,
1267 /* pfnSetParentModificationUuid */
1268 rawSetParentModificationUuid,
1269 /* pfnDump */
1270 rawDump,
1271 /* pfnGetTimeStamp */
1272 NULL,
1273 /* pfnGetParentTimeStamp */
1274 NULL,
1275 /* pfnSetParentTimeStamp */
1276 NULL,
1277 /* pfnGetParentFilename */
1278 NULL,
1279 /* pfnSetParentFilename */
1280 NULL,
1281 /* pfnAsyncRead */
1282 rawAsyncRead,
1283 /* pfnAsyncWrite */
1284 rawAsyncWrite,
1285 /* pfnAsyncFlush */
1286 rawAsyncFlush,
1287 /* pfnComposeLocation */
1288 genericFileComposeLocation,
1289 /* pfnComposeName */
1290 genericFileComposeName,
1291 /* pfnCompact */
1292 NULL,
1293 /* pfnResize */
1294 NULL,
1295 /* pfnDiscard */
1296 NULL,
1297 /* pfnAsyncDiscard */
1298 NULL,
1299 /* pfnRepair */
1300 NULL
1301};
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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