VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/RawHDDCore.cpp@ 33524

Last change on this file since 33524 was 33524, checked in by vboxsync, 14 years ago

Storage: Implement offical support for other disk types like DVD and floppy images. DMG images can be used now without hacks

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.0 KB
Line 
1/* $Id: RawHDDCore.cpp 33524 2010-10-27 16:44:37Z 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.virtualbox.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/VBoxHDD-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 * ISO volume descriptor.
35 */
36#pragma pack(1)
37typedef struct ISOVOLDESC
38{
39 union
40 {
41 /** Byte view. */
42 uint8_t au8[2048];
43 /** Field view. */
44 struct
45 {
46 /** Descriptor type. */
47 uint8_t u8Type;
48 /** Standard identifier */
49 uint8_t au8Id[5];
50 /** Descriptor version. */
51 uint8_t u8Version;
52 /** Rest depends on the descriptor type. */
53 } fields;
54 };
55} ISOVOLDESC, *PISOVOLDESC;
56#pragma pack()
57AssertCompileSize(ISOVOLDESC, 2048);
58
59/**
60 * Raw image data structure.
61 */
62typedef struct RAWIMAGE
63{
64 /** Image name. */
65 const char *pszFilename;
66 /** Storage handle. */
67 PVDIOSTORAGE pStorage;
68 /** I/O interface. */
69 PVDINTERFACE pInterfaceIO;
70 /** Async I/O interface callbacks. */
71 PVDINTERFACEIOINT pInterfaceIOCallbacks;
72
73 /** Pointer to the per-disk VD interface list. */
74 PVDINTERFACE pVDIfsDisk;
75 /** Pointer to the per-image VD interface list. */
76 PVDINTERFACE pVDIfsImage;
77
78 /** Error callback. */
79 PVDINTERFACE pInterfaceError;
80 /** Opaque data for error callback. */
81 PVDINTERFACEERROR pInterfaceErrorCallbacks;
82
83 /** Open flags passed by VBoxHD layer. */
84 unsigned uOpenFlags;
85 /** Image flags defined during creation or determined during open. */
86 unsigned uImageFlags;
87 /** Total size of the image. */
88 uint64_t cbSize;
89 /** Position in the image (only truly used for sequential access). */
90 uint64_t offAccess;
91 /** Flag if this is a newly created image. */
92 bool fCreate;
93 /** Physical geometry of this image. */
94 VDGEOMETRY PCHSGeometry;
95 /** Logical geometry of this image. */
96 VDGEOMETRY LCHSGeometry;
97
98} RAWIMAGE, *PRAWIMAGE;
99
100
101/** Size of write operations when filling an image with zeroes. */
102#define RAW_FILL_SIZE (128 * _1K)
103
104/*******************************************************************************
105* Static Variables *
106*******************************************************************************/
107
108/** NULL-terminated array of supported file extensions. */
109static const VDFILEEXTENSION s_aRawFileExtensions[] =
110{
111 {"iso", VDTYPE_DVD},
112 {"img", VDTYPE_FLOPPY},
113 {"ima", VDTYPE_FLOPPY},
114 {NULL, VDTYPE_INVALID}
115};
116
117/*******************************************************************************
118* Internal Functions *
119*******************************************************************************/
120
121/**
122 * Internal: signal an error to the frontend.
123 */
124DECLINLINE(int) rawError(PRAWIMAGE pImage, int rc, RT_SRC_POS_DECL,
125 const char *pszFormat, ...)
126{
127 va_list va;
128 va_start(va, pszFormat);
129 if (pImage->pInterfaceError)
130 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
131 pszFormat, va);
132 va_end(va);
133 return rc;
134}
135
136/**
137 * Internal: signal an informational message to the frontend.
138 */
139DECLINLINE(int) rawMessage(PRAWIMAGE pImage, const char *pszFormat, ...)
140{
141 int rc = VINF_SUCCESS;
142 va_list va;
143 va_start(va, pszFormat);
144 if (pImage->pInterfaceError)
145 rc = pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser,
146 pszFormat, va);
147 va_end(va);
148 return rc;
149}
150
151
152DECLINLINE(int) rawFileOpen(PRAWIMAGE pImage, const char *pszFilename,
153 uint32_t fOpen)
154{
155 return pImage->pInterfaceIOCallbacks->pfnOpen(pImage->pInterfaceIO->pvUser,
156 pszFilename, fOpen,
157 &pImage->pStorage);
158}
159
160DECLINLINE(int) rawFileClose(PRAWIMAGE pImage)
161{
162 return pImage->pInterfaceIOCallbacks->pfnClose(pImage->pInterfaceIO->pvUser,
163 pImage->pStorage);
164}
165
166DECLINLINE(int) rawFileDelete(PRAWIMAGE pImage, const char *pszFilename)
167{
168 return pImage->pInterfaceIOCallbacks->pfnDelete(pImage->pInterfaceIO->pvUser,
169 pszFilename);
170}
171
172DECLINLINE(int) rawFileMove(PRAWIMAGE pImage, const char *pszSrc,
173 const char *pszDst, unsigned fMove)
174{
175 return pImage->pInterfaceIOCallbacks->pfnMove(pImage->pInterfaceIO->pvUser,
176 pszSrc, pszDst, fMove);
177}
178
179DECLINLINE(int) rawFileGetFreeSpace(PRAWIMAGE pImage, const char *pszFilename,
180 int64_t *pcbFree)
181{
182 return pImage->pInterfaceIOCallbacks->pfnGetFreeSpace(pImage->pInterfaceIO->pvUser,
183 pszFilename, pcbFree);
184}
185
186DECLINLINE(int) rawFileGetSize(PRAWIMAGE pImage, uint64_t *pcbSize)
187{
188 return pImage->pInterfaceIOCallbacks->pfnGetSize(pImage->pInterfaceIO->pvUser,
189 pImage->pStorage, pcbSize);
190}
191
192DECLINLINE(int) rawFileSetSize(PRAWIMAGE pImage, uint64_t cbSize)
193{
194 return pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
195 pImage->pStorage, cbSize);
196}
197
198DECLINLINE(int) rawFileWriteSync(PRAWIMAGE pImage, uint64_t uOffset,
199 const void *pvBuffer, size_t cbBuffer,
200 size_t *pcbWritten)
201{
202 return pImage->pInterfaceIOCallbacks->pfnWriteSync(pImage->pInterfaceIO->pvUser,
203 pImage->pStorage, uOffset,
204 pvBuffer, cbBuffer, pcbWritten);
205}
206
207DECLINLINE(int) rawFileReadSync(PRAWIMAGE pImage, uint64_t uOffset,
208 void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
209{
210 return pImage->pInterfaceIOCallbacks->pfnReadSync(pImage->pInterfaceIO->pvUser,
211 pImage->pStorage, uOffset,
212 pvBuffer, cbBuffer, pcbRead);
213}
214
215DECLINLINE(int) rawFileFlushSync(PRAWIMAGE pImage)
216{
217 return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
218 pImage->pStorage);
219}
220
221DECLINLINE(int) rawFileReadUserAsync(PRAWIMAGE pImage, uint64_t uOffset,
222 PVDIOCTX pIoCtx, size_t cbRead)
223{
224 return pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
225 pImage->pStorage,
226 uOffset, pIoCtx,
227 cbRead);
228}
229
230DECLINLINE(int) rawFileWriteUserAsync(PRAWIMAGE pImage, uint64_t uOffset,
231 PVDIOCTX pIoCtx, size_t cbWrite,
232 PFNVDXFERCOMPLETED pfnComplete,
233 void *pvCompleteUser)
234{
235 return pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
236 pImage->pStorage,
237 uOffset, pIoCtx,
238 cbWrite,
239 pfnComplete,
240 pvCompleteUser);
241}
242
243DECLINLINE(int) rawFileFlushAsync(PRAWIMAGE pImage, PVDIOCTX pIoCtx,
244 PFNVDXFERCOMPLETED pfnComplete,
245 void *pvCompleteUser)
246{
247 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
248 pImage->pStorage,
249 pIoCtx, pfnComplete,
250 pvCompleteUser);
251}
252
253
254/**
255 * Internal. Flush image data to disk.
256 */
257static int rawFlushImage(PRAWIMAGE pImage)
258{
259 int rc = VINF_SUCCESS;
260
261 if ( pImage->pStorage
262 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
263 rc = rawFileFlushSync(pImage);
264
265 return rc;
266}
267
268/**
269 * Internal. Free all allocated space for representing an image except pImage,
270 * and optionally delete the image from disk.
271 */
272static int rawFreeImage(PRAWIMAGE pImage, bool fDelete)
273{
274 int rc = VINF_SUCCESS;
275
276 /* Freeing a never allocated image (e.g. because the open failed) is
277 * not signalled as an error. After all nothing bad happens. */
278 if (pImage)
279 {
280 if (pImage->pStorage)
281 {
282 /* No point updating the file that is deleted anyway. */
283 if (!fDelete)
284 {
285 /* For newly created images in sequential mode fill it to
286 * the nominal size. */
287 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
288 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
289 && pImage->fCreate)
290 {
291 /* Fill rest of image with zeroes, a must for sequential
292 * images to reach the nominal size. */
293 uint64_t uOff;
294 void *pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
295 if (!pvBuf)
296 goto out;
297
298 uOff = pImage->offAccess;
299 /* Write data to all image blocks. */
300 while (uOff < pImage->cbSize)
301 {
302 unsigned cbChunk = (unsigned)RT_MIN(pImage->cbSize,
303 RAW_FILL_SIZE);
304
305 rc = rawFileWriteSync(pImage, uOff, pvBuf, cbChunk,
306 NULL);
307 if (RT_FAILURE(rc))
308 goto out;
309
310 uOff += cbChunk;
311 }
312out:
313 if (pvBuf)
314 RTMemTmpFree(pvBuf);
315 }
316 rawFlushImage(pImage);
317 }
318
319 rawFileClose(pImage);
320 pImage->pStorage = NULL;
321 }
322
323 if (fDelete && pImage->pszFilename)
324 rawFileDelete(pImage, pImage->pszFilename);
325 }
326
327 LogFlowFunc(("returns %Rrc\n", rc));
328 return rc;
329}
330
331/**
332 * Internal: Open an image, constructing all necessary data structures.
333 */
334static int rawOpenImage(PRAWIMAGE pImage, unsigned uOpenFlags)
335{
336 int rc;
337
338 pImage->uOpenFlags = uOpenFlags;
339 pImage->fCreate = false;
340
341 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
342 if (pImage->pInterfaceError)
343 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
344
345 /* Get I/O interface. */
346 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
347 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
348 pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
349 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
350
351 /*
352 * Open the image.
353 */
354 rc = rawFileOpen(pImage, pImage->pszFilename,
355 VDOpenFlagsToFileOpenFlags(uOpenFlags,
356 false /* fCreate */));
357 if (RT_FAILURE(rc))
358 {
359 /* Do NOT signal an appropriate error here, as the VD layer has the
360 * choice of retrying the open if it failed. */
361 goto out;
362 }
363
364 rc = rawFileGetSize(pImage, &pImage->cbSize);
365 if (RT_FAILURE(rc))
366 goto out;
367 if (pImage->cbSize % 512)
368 {
369 rc = VERR_VD_RAW_INVALID_HEADER;
370 goto out;
371 }
372 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
373
374out:
375 if (RT_FAILURE(rc))
376 rawFreeImage(pImage, false);
377 return rc;
378}
379
380/**
381 * Internal: Create a raw image.
382 */
383static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize,
384 unsigned uImageFlags, const char *pszComment,
385 PCVDGEOMETRY pPCHSGeometry,
386 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
387 PFNVDPROGRESS pfnProgress, void *pvUser,
388 unsigned uPercentStart, unsigned uPercentSpan)
389{
390 int rc;
391 RTFOFF cbFree = 0;
392 uint64_t uOff;
393 void *pvBuf = NULL;
394 int32_t fOpen;
395
396 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
397 {
398 rc = rawError(pImage, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
399 goto out;
400 }
401 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
402
403 pImage->uImageFlags = uImageFlags;
404
405 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
406
407 pImage->uImageFlags = uImageFlags;
408 pImage->fCreate = true;
409 pImage->PCHSGeometry = *pPCHSGeometry;
410 pImage->LCHSGeometry = *pLCHSGeometry;
411
412 pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
413 if (pImage->pInterfaceError)
414 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
415
416 /* Get I/O interface. */
417 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IOINT);
418 AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
419 pImage->pInterfaceIOCallbacks = VDGetInterfaceIOInt(pImage->pInterfaceIO);
420 AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
421
422 /* Create image file. */
423 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
424 if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
425 fOpen &= ~RTFILE_O_READ;
426 rc = rawFileOpen(pImage, pImage->pszFilename, fOpen);
427 if (RT_FAILURE(rc))
428 {
429 rc = rawError(pImage, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
430 goto out;
431 }
432
433 if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
434 {
435 /* Check the free space on the disk and leave early if there is not
436 * sufficient space available. */
437 rc = rawFileGetFreeSpace(pImage, pImage->pszFilename, &cbFree);
438 if (RT_SUCCESS(rc) /* ignore errors */ && ((uint64_t)cbFree < cbSize))
439 {
440 rc = rawError(pImage, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
441 goto out;
442 }
443
444 /* Allocate & commit whole file if fixed image, it must be more
445 * effective than expanding file by write operations. */
446 rc = rawFileSetSize(pImage, cbSize);
447 if (RT_FAILURE(rc))
448 {
449 rc = rawError(pImage, rc, RT_SRC_POS, N_("Raw: setting image size failed for '%s'"), pImage->pszFilename);
450 goto out;
451 }
452
453 /* Fill image with zeroes. We do this for every fixed-size image since
454 * on some systems (for example Windows Vista), it takes ages to write
455 * a block near the end of a sparse file and the guest could complain
456 * about an ATA timeout. */
457 pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
458 if (!pvBuf)
459 {
460 rc = VERR_NO_MEMORY;
461 goto out;
462 }
463
464 uOff = 0;
465 /* Write data to all image blocks. */
466 while (uOff < cbSize)
467 {
468 unsigned cbChunk = (unsigned)RT_MIN(cbSize, RAW_FILL_SIZE);
469
470 rc = rawFileWriteSync(pImage, uOff, pvBuf, cbChunk, NULL);
471 if (RT_FAILURE(rc))
472 {
473 rc = rawError(pImage, rc, RT_SRC_POS, N_("Raw: writing block failed for '%s'"), pImage->pszFilename);
474 goto out;
475 }
476
477 uOff += cbChunk;
478
479 if (pfnProgress)
480 {
481 rc = pfnProgress(pvUser,
482 uPercentStart + uOff * uPercentSpan * 98 / (cbSize * 100));
483 if (RT_FAILURE(rc))
484 goto out;
485 }
486 }
487 }
488
489 if (RT_SUCCESS(rc) && pfnProgress)
490 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
491
492 pImage->cbSize = cbSize;
493
494 rc = rawFlushImage(pImage);
495
496out:
497 if (pvBuf)
498 RTMemTmpFree(pvBuf);
499
500 if (RT_SUCCESS(rc) && pfnProgress)
501 pfnProgress(pvUser, uPercentStart + uPercentSpan);
502
503 if (RT_FAILURE(rc))
504 rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
505 return rc;
506}
507
508
509/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
510static int rawCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
511 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
512{
513 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
514 PVDIOSTORAGE pStorage = NULL;
515 uint64_t cbFile;
516 int rc = VINF_SUCCESS;
517 ISOVOLDESC IsoVolDesc;
518 char *pszExtension = NULL;
519
520 /* Get I/O interface. */
521 PVDINTERFACE pInterfaceIO = VDInterfaceGet(pVDIfsImage, VDINTERFACETYPE_IOINT);
522 AssertPtrReturn(pInterfaceIO, VERR_INVALID_PARAMETER);
523 PVDINTERFACEIOINT pInterfaceIOCallbacks = VDGetInterfaceIOInt(pInterfaceIO);
524 AssertPtrReturn(pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
525
526 if ( !VALID_PTR(pszFilename)
527 || !*pszFilename)
528 {
529 rc = VERR_INVALID_PARAMETER;
530 goto out;
531 }
532
533 pszExtension = RTPathExt(pszFilename);
534
535 /*
536 * Open the file and read the footer.
537 */
538 rc = pInterfaceIOCallbacks->pfnOpen(pInterfaceIO->pvUser, pszFilename,
539 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
540 false /* fCreate */),
541 &pStorage);
542 if (RT_SUCCESS(rc))
543 rc = pInterfaceIOCallbacks->pfnGetSize(pInterfaceIO->pvUser, pStorage,
544 &cbFile);
545
546 /* Try to guess the image type based on the extension. */
547 if ( RT_SUCCESS(rc)
548 && pszExtension)
549 {
550 if (!strcmp(pszExtension, ".iso")) /* DVD images. */
551 {
552 if (cbFile >= (32768 + sizeof(ISOVOLDESC)))
553 {
554 rc = pInterfaceIOCallbacks->pfnReadSync(pInterfaceIO->pvUser, pStorage,
555 32768, &IsoVolDesc, sizeof(IsoVolDesc), NULL);
556 }
557 else
558 rc = VERR_VD_RAW_INVALID_HEADER;
559
560 if (RT_SUCCESS(rc))
561 {
562 /*
563 * Do we recognize this stuff?
564 */
565 if ( !memcmp(IsoVolDesc.fields.au8Id, "BEA01", 5)
566 || !memcmp(IsoVolDesc.fields.au8Id, "BOOT2", 5)
567 || !memcmp(IsoVolDesc.fields.au8Id, "CD001", 5)
568 || !memcmp(IsoVolDesc.fields.au8Id, "CDW02", 5)
569 || !memcmp(IsoVolDesc.fields.au8Id, "NSR02", 5)
570 || !memcmp(IsoVolDesc.fields.au8Id, "NSR03", 5)
571 || !memcmp(IsoVolDesc.fields.au8Id, "TEA01", 5))
572 {
573 *penmType = VDTYPE_DVD;
574 rc = VINF_SUCCESS;
575 }
576 else
577 rc = VERR_VD_RAW_INVALID_HEADER;
578 }
579 }
580 else if (!strcmp(pszExtension, ".img") || !strcmp(pszExtension, ".ima")) /* Floppy images */
581 {
582 if (!(cbFile % 512))
583 {
584 *penmType = VDTYPE_FLOPPY;
585 rc = VINF_SUCCESS;
586 }
587 else
588 rc = VERR_VD_RAW_INVALID_HEADER;
589 }
590 }
591 else
592 rc = VERR_VD_RAW_INVALID_HEADER;
593
594 if (pStorage)
595 pInterfaceIOCallbacks->pfnClose(pInterfaceIO->pvUser, pStorage);
596
597out:
598 LogFlowFunc(("returns %Rrc\n", rc));
599 return rc;
600}
601
602/** @copydoc VBOXHDDBACKEND::pfnOpen */
603static int rawOpen(const char *pszFilename, unsigned uOpenFlags,
604 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
605 VDTYPE enmType, void **ppBackendData)
606{
607 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
608 int rc;
609 PRAWIMAGE pImage;
610
611 /* Check open flags. All valid flags are supported. */
612 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
613 {
614 rc = VERR_INVALID_PARAMETER;
615 goto out;
616 }
617
618 /* Check remaining arguments. */
619 if ( !VALID_PTR(pszFilename)
620 || !*pszFilename)
621 {
622 rc = VERR_INVALID_PARAMETER;
623 goto out;
624 }
625
626
627 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
628 if (!pImage)
629 {
630 rc = VERR_NO_MEMORY;
631 goto out;
632 }
633 pImage->pszFilename = pszFilename;
634 pImage->pStorage = NULL;
635 pImage->pVDIfsDisk = pVDIfsDisk;
636 pImage->pVDIfsImage = pVDIfsImage;
637
638 rc = rawOpenImage(pImage, uOpenFlags);
639 if (RT_SUCCESS(rc))
640 *ppBackendData = pImage;
641 else
642 RTMemFree(pImage);
643
644out:
645 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
646 return rc;
647}
648
649/** @copydoc VBOXHDDBACKEND::pfnCreate */
650static int rawCreate(const char *pszFilename, uint64_t cbSize,
651 unsigned uImageFlags, const char *pszComment,
652 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
653 PCRTUUID pUuid, unsigned uOpenFlags,
654 unsigned uPercentStart, unsigned uPercentSpan,
655 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
656 PVDINTERFACE pVDIfsOperation, void **ppBackendData)
657{
658 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));
659 int rc;
660 PRAWIMAGE pImage;
661
662 PFNVDPROGRESS pfnProgress = NULL;
663 void *pvUser = NULL;
664 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
665 VDINTERFACETYPE_PROGRESS);
666 PVDINTERFACEPROGRESS pCbProgress = NULL;
667 if (pIfProgress)
668 {
669 pCbProgress = VDGetInterfaceProgress(pIfProgress);
670 if (pCbProgress)
671 pfnProgress = pCbProgress->pfnProgress;
672 pvUser = pIfProgress->pvUser;
673 }
674
675 /* Check open flags. All valid flags are supported. */
676 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
677 {
678 rc = VERR_INVALID_PARAMETER;
679 goto out;
680 }
681
682 /* Check remaining arguments. */
683 if ( !VALID_PTR(pszFilename)
684 || !*pszFilename
685 || !VALID_PTR(pPCHSGeometry)
686 || !VALID_PTR(pLCHSGeometry))
687 {
688 rc = VERR_INVALID_PARAMETER;
689 goto out;
690 }
691
692 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
693 if (!pImage)
694 {
695 rc = VERR_NO_MEMORY;
696 goto out;
697 }
698 pImage->pszFilename = pszFilename;
699 pImage->pStorage = NULL;
700 pImage->pVDIfsDisk = pVDIfsDisk;
701 pImage->pVDIfsImage = pVDIfsImage;
702
703 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
704 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
705 pfnProgress, pvUser, uPercentStart, uPercentSpan);
706 if (RT_SUCCESS(rc))
707 {
708 /* So far the image is opened in read/write mode. Make sure the
709 * image is opened in read-only mode if the caller requested that. */
710 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
711 {
712 rawFreeImage(pImage, false);
713 rc = rawOpenImage(pImage, uOpenFlags);
714 if (RT_FAILURE(rc))
715 {
716 RTMemFree(pImage);
717 goto out;
718 }
719 }
720 *ppBackendData = pImage;
721 }
722 else
723 RTMemFree(pImage);
724
725out:
726 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
727 return rc;
728}
729
730/** @copydoc VBOXHDDBACKEND::pfnRename */
731static int rawRename(void *pBackendData, const char *pszFilename)
732{
733 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
734 int rc = VINF_SUCCESS;
735 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
736
737 /* Check arguments. */
738 if ( !pImage
739 || !pszFilename
740 || !*pszFilename)
741 {
742 rc = VERR_INVALID_PARAMETER;
743 goto out;
744 }
745
746 /* Close the image. */
747 rc = rawFreeImage(pImage, false);
748 if (RT_FAILURE(rc))
749 goto out;
750
751 /* Rename the file. */
752 rc = rawFileMove(pImage, pImage->pszFilename, pszFilename, 0);
753 if (RT_FAILURE(rc))
754 {
755 /* The move failed, try to reopen the original image. */
756 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
757 if (RT_FAILURE(rc2))
758 rc = rc2;
759
760 goto out;
761 }
762
763 /* Update pImage with the new information. */
764 pImage->pszFilename = pszFilename;
765
766 /* Open the old image with new name. */
767 rc = rawOpenImage(pImage, pImage->uOpenFlags);
768 if (RT_FAILURE(rc))
769 goto out;
770
771out:
772 LogFlowFunc(("returns %Rrc\n", rc));
773 return rc;
774}
775
776/** @copydoc VBOXHDDBACKEND::pfnClose */
777static int rawClose(void *pBackendData, bool fDelete)
778{
779 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
780 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
781 int rc;
782
783 rc = rawFreeImage(pImage, fDelete);
784 RTMemFree(pImage);
785
786 LogFlowFunc(("returns %Rrc\n", rc));
787 return rc;
788}
789
790/** @copydoc VBOXHDDBACKEND::pfnRead */
791static int rawRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
792 size_t cbToRead, size_t *pcbActuallyRead)
793{
794 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
795 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
796 int rc;
797
798 AssertPtr(pImage);
799 Assert(uOffset % 512 == 0);
800 Assert(cbToRead % 512 == 0);
801
802 if ( uOffset + cbToRead > pImage->cbSize
803 || cbToRead == 0)
804 {
805 rc = VERR_INVALID_PARAMETER;
806 goto out;
807 }
808
809 /* For sequential access do not allow to go back. */
810 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
811 && uOffset < pImage->offAccess)
812 {
813 rc = VERR_INVALID_PARAMETER;
814 goto out;
815 }
816
817 rc = rawFileReadSync(pImage, uOffset, pvBuf, cbToRead, NULL);
818 pImage->offAccess = uOffset + cbToRead;
819 if (pcbActuallyRead)
820 *pcbActuallyRead = cbToRead;
821
822out:
823 LogFlowFunc(("returns %Rrc\n", rc));
824 return rc;
825}
826
827/** @copydoc VBOXHDDBACKEND::pfnWrite */
828static int rawWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
829 size_t cbToWrite, size_t *pcbWriteProcess,
830 size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
831{
832 LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
833 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
834 int rc;
835
836 AssertPtr(pImage);
837 Assert(uOffset % 512 == 0);
838 Assert(cbToWrite % 512 == 0);
839
840 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
841 {
842 rc = VERR_VD_IMAGE_READ_ONLY;
843 goto out;
844 }
845
846 if ( uOffset + cbToWrite > pImage->cbSize
847 || cbToWrite == 0)
848 {
849 rc = VERR_INVALID_PARAMETER;
850 goto out;
851 }
852
853 /* For sequential access do not allow to go back. */
854 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
855 && uOffset < pImage->offAccess)
856 {
857 rc = VERR_INVALID_PARAMETER;
858 goto out;
859 }
860
861 rc = rawFileWriteSync(pImage, uOffset, pvBuf, cbToWrite, NULL);
862 pImage->offAccess = uOffset + cbToWrite;
863 if (pcbWriteProcess)
864 *pcbWriteProcess = cbToWrite;
865
866out:
867 LogFlowFunc(("returns %Rrc\n", rc));
868 return rc;
869}
870
871/** @copydoc VBOXHDDBACKEND::pfnFlush */
872static int rawFlush(void *pBackendData)
873{
874 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
875 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
876 int rc;
877
878 rc = rawFlushImage(pImage);
879 LogFlowFunc(("returns %Rrc\n", rc));
880 return rc;
881}
882
883/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
884static unsigned rawGetVersion(void *pBackendData)
885{
886 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
887 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
888
889 AssertPtr(pImage);
890
891 if (pImage)
892 return 1;
893 else
894 return 0;
895}
896
897/** @copydoc VBOXHDDBACKEND::pfnGetSize */
898static uint64_t rawGetSize(void *pBackendData)
899{
900 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
901 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
902 uint64_t cb = 0;
903
904 AssertPtr(pImage);
905
906 if (pImage && pImage->pStorage)
907 cb = pImage->cbSize;
908
909 LogFlowFunc(("returns %llu\n", cb));
910 return cb;
911}
912
913/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
914static uint64_t rawGetFileSize(void *pBackendData)
915{
916 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
917 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
918 uint64_t cb = 0;
919
920 AssertPtr(pImage);
921
922 if (pImage)
923 {
924 uint64_t cbFile;
925 if (pImage->pStorage)
926 {
927 int rc = rawFileGetSize(pImage, &cbFile);
928 if (RT_SUCCESS(rc))
929 cb += cbFile;
930 }
931 }
932
933 LogFlowFunc(("returns %lld\n", cb));
934 return cb;
935}
936
937/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
938static int rawGetPCHSGeometry(void *pBackendData,
939 PVDGEOMETRY pPCHSGeometry)
940{
941 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
942 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
943 int rc;
944
945 AssertPtr(pImage);
946
947 if (pImage)
948 {
949 if (pImage->PCHSGeometry.cCylinders)
950 {
951 *pPCHSGeometry = pImage->PCHSGeometry;
952 rc = VINF_SUCCESS;
953 }
954 else
955 rc = VERR_VD_GEOMETRY_NOT_SET;
956 }
957 else
958 rc = VERR_VD_NOT_OPENED;
959
960 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
961 return rc;
962}
963
964/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
965static int rawSetPCHSGeometry(void *pBackendData,
966 PCVDGEOMETRY pPCHSGeometry)
967{
968 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
969 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
970 int rc;
971
972 AssertPtr(pImage);
973
974 if (pImage)
975 {
976 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
977 {
978 rc = VERR_VD_IMAGE_READ_ONLY;
979 goto out;
980 }
981
982 pImage->PCHSGeometry = *pPCHSGeometry;
983 rc = VINF_SUCCESS;
984 }
985 else
986 rc = VERR_VD_NOT_OPENED;
987
988out:
989 LogFlowFunc(("returns %Rrc\n", rc));
990 return rc;
991}
992
993/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
994static int rawGetLCHSGeometry(void *pBackendData,
995 PVDGEOMETRY pLCHSGeometry)
996{
997 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
998 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
999 int rc;
1000
1001 AssertPtr(pImage);
1002
1003 if (pImage)
1004 {
1005 if (pImage->LCHSGeometry.cCylinders)
1006 {
1007 *pLCHSGeometry = pImage->LCHSGeometry;
1008 rc = VINF_SUCCESS;
1009 }
1010 else
1011 rc = VERR_VD_GEOMETRY_NOT_SET;
1012 }
1013 else
1014 rc = VERR_VD_NOT_OPENED;
1015
1016 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1017 return rc;
1018}
1019
1020/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
1021static int rawSetLCHSGeometry(void *pBackendData,
1022 PCVDGEOMETRY pLCHSGeometry)
1023{
1024 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1025 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1026 int rc;
1027
1028 AssertPtr(pImage);
1029
1030 if (pImage)
1031 {
1032 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1033 {
1034 rc = VERR_VD_IMAGE_READ_ONLY;
1035 goto out;
1036 }
1037
1038 pImage->LCHSGeometry = *pLCHSGeometry;
1039 rc = VINF_SUCCESS;
1040 }
1041 else
1042 rc = VERR_VD_NOT_OPENED;
1043
1044out:
1045 LogFlowFunc(("returns %Rrc\n", rc));
1046 return rc;
1047}
1048
1049/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
1050static unsigned rawGetImageFlags(void *pBackendData)
1051{
1052 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1053 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1054 unsigned uImageFlags;
1055
1056 AssertPtr(pImage);
1057
1058 if (pImage)
1059 uImageFlags = pImage->uImageFlags;
1060 else
1061 uImageFlags = 0;
1062
1063 LogFlowFunc(("returns %#x\n", uImageFlags));
1064 return uImageFlags;
1065}
1066
1067/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
1068static unsigned rawGetOpenFlags(void *pBackendData)
1069{
1070 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1071 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1072 unsigned uOpenFlags;
1073
1074 AssertPtr(pImage);
1075
1076 if (pImage)
1077 uOpenFlags = pImage->uOpenFlags;
1078 else
1079 uOpenFlags = 0;
1080
1081 LogFlowFunc(("returns %#x\n", uOpenFlags));
1082 return uOpenFlags;
1083}
1084
1085/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
1086static int rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
1087{
1088 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
1089 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1090 int rc;
1091
1092 /* Image must be opened and the new flags must be valid. */
1093 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
1094 {
1095 rc = VERR_INVALID_PARAMETER;
1096 goto out;
1097 }
1098
1099 /* Implement this operation via reopening the image. */
1100 rc = rawFreeImage(pImage, false);
1101 if (RT_FAILURE(rc))
1102 goto out;
1103 rc = rawOpenImage(pImage, uOpenFlags);
1104
1105out:
1106 LogFlowFunc(("returns %Rrc\n", rc));
1107 return rc;
1108}
1109
1110/** @copydoc VBOXHDDBACKEND::pfnGetComment */
1111static int rawGetComment(void *pBackendData, char *pszComment,
1112 size_t cbComment)
1113{
1114 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
1115 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1116 int rc;
1117
1118 AssertPtr(pImage);
1119
1120 if (pImage)
1121 rc = VERR_NOT_SUPPORTED;
1122 else
1123 rc = VERR_VD_NOT_OPENED;
1124
1125 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
1126 return rc;
1127}
1128
1129/** @copydoc VBOXHDDBACKEND::pfnSetComment */
1130static int rawSetComment(void *pBackendData, const char *pszComment)
1131{
1132 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
1133 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1134 int rc;
1135
1136 AssertPtr(pImage);
1137
1138 if (pImage)
1139 {
1140 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
1141 rc = VERR_VD_IMAGE_READ_ONLY;
1142 else
1143 rc = VERR_NOT_SUPPORTED;
1144 }
1145 else
1146 rc = VERR_VD_NOT_OPENED;
1147
1148out:
1149 LogFlowFunc(("returns %Rrc\n", rc));
1150 return rc;
1151}
1152
1153/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
1154static int rawGetUuid(void *pBackendData, PRTUUID pUuid)
1155{
1156 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1157 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1158 int rc;
1159
1160 AssertPtr(pImage);
1161
1162 if (pImage)
1163 rc = VERR_NOT_SUPPORTED;
1164 else
1165 rc = VERR_VD_NOT_OPENED;
1166
1167 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1168 return rc;
1169}
1170
1171/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
1172static int rawSetUuid(void *pBackendData, PCRTUUID pUuid)
1173{
1174 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1175 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1176 int rc;
1177
1178 LogFlowFunc(("%RTuuid\n", pUuid));
1179 AssertPtr(pImage);
1180
1181 if (pImage)
1182 {
1183 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1184 rc = VERR_NOT_SUPPORTED;
1185 else
1186 rc = VERR_VD_IMAGE_READ_ONLY;
1187 }
1188 else
1189 rc = VERR_VD_NOT_OPENED;
1190
1191 LogFlowFunc(("returns %Rrc\n", rc));
1192 return rc;
1193}
1194
1195/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1196static int rawGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1197{
1198 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1199 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1200 int rc;
1201
1202 AssertPtr(pImage);
1203
1204 if (pImage)
1205 rc = VERR_NOT_SUPPORTED;
1206 else
1207 rc = VERR_VD_NOT_OPENED;
1208
1209 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1210 return rc;
1211}
1212
1213/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1214static int rawSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1215{
1216 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1217 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1218 int rc;
1219
1220 AssertPtr(pImage);
1221
1222 if (pImage)
1223 {
1224 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1225 rc = VERR_NOT_SUPPORTED;
1226 else
1227 rc = VERR_VD_IMAGE_READ_ONLY;
1228 }
1229 else
1230 rc = VERR_VD_NOT_OPENED;
1231
1232 LogFlowFunc(("returns %Rrc\n", rc));
1233 return rc;
1234}
1235
1236/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1237static int rawGetParentUuid(void *pBackendData, PRTUUID pUuid)
1238{
1239 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1240 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1241 int rc;
1242
1243 AssertPtr(pImage);
1244
1245 if (pImage)
1246 rc = VERR_NOT_SUPPORTED;
1247 else
1248 rc = VERR_VD_NOT_OPENED;
1249
1250 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1251 return rc;
1252}
1253
1254/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1255static int rawSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1256{
1257 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1258 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1259 int rc;
1260
1261 AssertPtr(pImage);
1262
1263 if (pImage)
1264 {
1265 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1266 rc = VERR_NOT_SUPPORTED;
1267 else
1268 rc = VERR_VD_IMAGE_READ_ONLY;
1269 }
1270 else
1271 rc = VERR_VD_NOT_OPENED;
1272
1273 LogFlowFunc(("returns %Rrc\n", rc));
1274 return rc;
1275}
1276
1277/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1278static int rawGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1279{
1280 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1281 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1282 int rc;
1283
1284 AssertPtr(pImage);
1285
1286 if (pImage)
1287 rc = VERR_NOT_SUPPORTED;
1288 else
1289 rc = VERR_VD_NOT_OPENED;
1290
1291 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1292 return rc;
1293}
1294
1295/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1296static int rawSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1297{
1298 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1299 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1300 int rc;
1301
1302 AssertPtr(pImage);
1303
1304 if (pImage)
1305 {
1306 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1307 rc = VERR_NOT_SUPPORTED;
1308 else
1309 rc = VERR_VD_IMAGE_READ_ONLY;
1310 }
1311 else
1312 rc = VERR_VD_NOT_OPENED;
1313
1314 LogFlowFunc(("returns %Rrc\n", rc));
1315 return rc;
1316}
1317
1318/** @copydoc VBOXHDDBACKEND::pfnDump */
1319static void rawDump(void *pBackendData)
1320{
1321 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1322
1323 AssertPtr(pImage);
1324 if (pImage)
1325 {
1326 rawMessage(pImage, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
1327 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1328 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
1329 pImage->cbSize / 512);
1330 }
1331}
1332
1333/** @copydoc VBOXHDDBACKEND::pfnIsAsyncIOSupported */
1334static bool rawIsAsyncIOSupported(void *pBackendData)
1335{
1336 return true;
1337}
1338
1339/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
1340static int rawAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
1341 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
1342{
1343 int rc = VINF_SUCCESS;
1344 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1345
1346 rc = rawFileReadUserAsync(pImage, uOffset, pIoCtx, cbRead);
1347 if (RT_SUCCESS(rc))
1348 *pcbActuallyRead = cbRead;
1349
1350 return rc;
1351}
1352
1353/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
1354static int rawAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
1355 PVDIOCTX pIoCtx,
1356 size_t *pcbWriteProcess, size_t *pcbPreRead,
1357 size_t *pcbPostRead, unsigned fWrite)
1358{
1359 int rc = VINF_SUCCESS;
1360 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1361
1362 rc = rawFileWriteUserAsync(pImage, uOffset, pIoCtx, cbWrite, NULL, NULL);
1363 if (RT_SUCCESS(rc))
1364 {
1365 *pcbWriteProcess = cbWrite;
1366 *pcbPostRead = 0;
1367 *pcbPreRead = 0;
1368 }
1369
1370 return rc;
1371}
1372
1373/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
1374static int rawAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
1375{
1376 int rc = VINF_SUCCESS;
1377 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1378
1379 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1380 rc = rawFileFlushAsync(pImage, pIoCtx, NULL, NULL);
1381
1382 return rc;
1383}
1384
1385
1386VBOXHDDBACKEND g_RawBackend =
1387{
1388 /* pszBackendName */
1389 "RAW",
1390 /* cbSize */
1391 sizeof(VBOXHDDBACKEND),
1392 /* uBackendCaps */
1393 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1394 /* paFileExtensions */
1395 s_aRawFileExtensions,
1396 /* paConfigInfo */
1397 NULL,
1398 /* hPlugin */
1399 NIL_RTLDRMOD,
1400 /* pfnCheckIfValid */
1401 rawCheckIfValid,
1402 /* pfnOpen */
1403 rawOpen,
1404 /* pfnCreate */
1405 rawCreate,
1406 /* pfnRename */
1407 rawRename,
1408 /* pfnClose */
1409 rawClose,
1410 /* pfnRead */
1411 rawRead,
1412 /* pfnWrite */
1413 rawWrite,
1414 /* pfnFlush */
1415 rawFlush,
1416 /* pfnGetVersion */
1417 rawGetVersion,
1418 /* pfnGetSize */
1419 rawGetSize,
1420 /* pfnGetFileSize */
1421 rawGetFileSize,
1422 /* pfnGetPCHSGeometry */
1423 rawGetPCHSGeometry,
1424 /* pfnSetPCHSGeometry */
1425 rawSetPCHSGeometry,
1426 /* pfnGetLCHSGeometry */
1427 rawGetLCHSGeometry,
1428 /* pfnSetLCHSGeometry */
1429 rawSetLCHSGeometry,
1430 /* pfnGetImageFlags */
1431 rawGetImageFlags,
1432 /* pfnGetOpenFlags */
1433 rawGetOpenFlags,
1434 /* pfnSetOpenFlags */
1435 rawSetOpenFlags,
1436 /* pfnGetComment */
1437 rawGetComment,
1438 /* pfnSetComment */
1439 rawSetComment,
1440 /* pfnGetUuid */
1441 rawGetUuid,
1442 /* pfnSetUuid */
1443 rawSetUuid,
1444 /* pfnGetModificationUuid */
1445 rawGetModificationUuid,
1446 /* pfnSetModificationUuid */
1447 rawSetModificationUuid,
1448 /* pfnGetParentUuid */
1449 rawGetParentUuid,
1450 /* pfnSetParentUuid */
1451 rawSetParentUuid,
1452 /* pfnGetParentModificationUuid */
1453 rawGetParentModificationUuid,
1454 /* pfnSetParentModificationUuid */
1455 rawSetParentModificationUuid,
1456 /* pfnDump */
1457 rawDump,
1458 /* pfnGetTimeStamp */
1459 NULL,
1460 /* pfnGetParentTimeStamp */
1461 NULL,
1462 /* pfnSetParentTimeStamp */
1463 NULL,
1464 /* pfnGetParentFilename */
1465 NULL,
1466 /* pfnSetParentFilename */
1467 NULL,
1468 /* pfnIsAsyncIOSupported */
1469 rawIsAsyncIOSupported,
1470 /* pfnAsyncRead */
1471 rawAsyncRead,
1472 /* pfnAsyncWrite */
1473 rawAsyncWrite,
1474 /* pfnAsyncFlush */
1475 rawAsyncFlush,
1476 /* pfnComposeLocation */
1477 genericFileComposeLocation,
1478 /* pfnComposeName */
1479 genericFileComposeName,
1480 /* pfnCompact */
1481 NULL,
1482 /* pfnResize */
1483 NULL
1484};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use