VirtualBox

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

Last change on this file since 48950 was 48743, checked in by vboxsync, 11 years ago

Storage/VD: Add support for different sector sizes (only opening and reading and writing images, not creating them with a sector size other than 512 bytes)

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