VirtualBox

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

Last change on this file since 59455 was 59455, checked in by vboxsync, 9 years ago

Storage/VD: Remove the custom code in each backend which allocates all blocks in a fixed size image by writing zeros to it. Preparations to make use of more optimized methods to allocate large files on recent hosts (fallocate() and friends)

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

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