VirtualBox

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

Last change on this file since 52902 was 50988, checked in by vboxsync, 11 years ago

Storage/VD: Cleanup VD plugin handling. One shared object can now support an arbitrary number of image backends instead of just one like before

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

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