VirtualBox

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

Last change on this file since 55180 was 54430, checked in by vboxsync, 10 years ago

Storage/VD: make use of the image type (hdd/dvd/floppy) for sanity checking when creating disk images

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1/* $Id: RAW.cpp 54430 2015-02-24 10:43:16Z 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* 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 - uOff, 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 enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
430 int rc;
431 PRAWIMAGE pImage;
432
433 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
434
435 /* Check open flags. All valid flags are supported. */
436 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
437 {
438 rc = VERR_INVALID_PARAMETER;
439 goto out;
440 }
441
442 /* Check remaining arguments. */
443 if ( !VALID_PTR(pszFilename)
444 || !*pszFilename)
445 {
446 rc = VERR_INVALID_PARAMETER;
447 goto out;
448 }
449
450
451 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
452 if (!pImage)
453 {
454 rc = VERR_NO_MEMORY;
455 goto out;
456 }
457 pImage->pszFilename = pszFilename;
458 pImage->pStorage = NULL;
459 pImage->pVDIfsDisk = pVDIfsDisk;
460 pImage->pVDIfsImage = pVDIfsImage;
461
462 rc = rawOpenImage(pImage, uOpenFlags);
463 if (RT_SUCCESS(rc))
464 {
465 if (enmType == VDTYPE_DVD)
466 pImage->cbSector = 2048;
467 else
468 pImage->cbSector = 512;
469 *ppBackendData = pImage;
470 }
471 else
472 RTMemFree(pImage);
473
474out:
475 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
476 return rc;
477}
478
479/** @copydoc VBOXHDDBACKEND::pfnCreate */
480static int rawCreate(const char *pszFilename, uint64_t cbSize,
481 unsigned uImageFlags, const char *pszComment,
482 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
483 PCRTUUID pUuid, unsigned uOpenFlags,
484 unsigned uPercentStart, unsigned uPercentSpan,
485 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
486 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
487 void **ppBackendData)
488{
489 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",
490 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
491 int rc;
492 PRAWIMAGE pImage;
493
494 PFNVDPROGRESS pfnProgress = NULL;
495 void *pvUser = NULL;
496 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
497 if (pIfProgress)
498 {
499 pfnProgress = pIfProgress->pfnProgress;
500 pvUser = pIfProgress->Core.pvUser;
501 }
502
503 /* Check the VD container type. Yes, hard disk must be allowed, otherwise
504 * various tools using this backend for hard disk images will fail. */
505 if (enmType != VDTYPE_HDD && enmType != VDTYPE_DVD && enmType != VDTYPE_FLOPPY)
506 {
507 rc = VERR_VD_INVALID_TYPE;
508 goto out;
509 }
510
511 /* Check open flags. All valid flags are supported. */
512 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
513 {
514 rc = VERR_INVALID_PARAMETER;
515 goto out;
516 }
517
518 /* Check remaining arguments. */
519 if ( !VALID_PTR(pszFilename)
520 || !*pszFilename
521 || !VALID_PTR(pPCHSGeometry)
522 || !VALID_PTR(pLCHSGeometry))
523 {
524 rc = VERR_INVALID_PARAMETER;
525 goto out;
526 }
527
528 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
529 if (!pImage)
530 {
531 rc = VERR_NO_MEMORY;
532 goto out;
533 }
534 pImage->pszFilename = pszFilename;
535 pImage->pStorage = NULL;
536 pImage->pVDIfsDisk = pVDIfsDisk;
537 pImage->pVDIfsImage = pVDIfsImage;
538
539 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
540 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
541 pfnProgress, pvUser, uPercentStart, uPercentSpan);
542 if (RT_SUCCESS(rc))
543 {
544 /* So far the image is opened in read/write mode. Make sure the
545 * image is opened in read-only mode if the caller requested that. */
546 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
547 {
548 rawFreeImage(pImage, false);
549 rc = rawOpenImage(pImage, uOpenFlags);
550 if (RT_FAILURE(rc))
551 {
552 RTMemFree(pImage);
553 goto out;
554 }
555 }
556 *ppBackendData = pImage;
557 }
558 else
559 RTMemFree(pImage);
560
561out:
562 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
563 return rc;
564}
565
566/** @copydoc VBOXHDDBACKEND::pfnRename */
567static int rawRename(void *pBackendData, const char *pszFilename)
568{
569 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
570 int rc = VINF_SUCCESS;
571 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
572
573 /* Check arguments. */
574 if ( !pImage
575 || !pszFilename
576 || !*pszFilename)
577 {
578 rc = VERR_INVALID_PARAMETER;
579 goto out;
580 }
581
582 /* Close the image. */
583 rc = rawFreeImage(pImage, false);
584 if (RT_FAILURE(rc))
585 goto out;
586
587 /* Rename the file. */
588 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
589 if (RT_FAILURE(rc))
590 {
591 /* The move failed, try to reopen the original image. */
592 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
593 if (RT_FAILURE(rc2))
594 rc = rc2;
595
596 goto out;
597 }
598
599 /* Update pImage with the new information. */
600 pImage->pszFilename = pszFilename;
601
602 /* Open the old image with new name. */
603 rc = rawOpenImage(pImage, pImage->uOpenFlags);
604 if (RT_FAILURE(rc))
605 goto out;
606
607out:
608 LogFlowFunc(("returns %Rrc\n", rc));
609 return rc;
610}
611
612/** @copydoc VBOXHDDBACKEND::pfnClose */
613static int rawClose(void *pBackendData, bool fDelete)
614{
615 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
616 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
617 int rc;
618
619 rc = rawFreeImage(pImage, fDelete);
620 RTMemFree(pImage);
621
622 LogFlowFunc(("returns %Rrc\n", rc));
623 return rc;
624}
625
626/** @copydoc VBOXHDDBACKEND::pfnRead */
627static int rawRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
628 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
629{
630 int rc = VINF_SUCCESS;
631 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
632
633 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
634 pIoCtx, cbRead);
635 if (RT_SUCCESS(rc))
636 *pcbActuallyRead = cbRead;
637
638 return rc;
639}
640
641/** @copydoc VBOXHDDBACKEND::pfnWrite */
642static int rawWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
643 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
644 size_t *pcbPostRead, unsigned fWrite)
645{
646 int rc = VINF_SUCCESS;
647 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
648
649 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
650 pIoCtx, cbWrite, NULL, NULL);
651 if (RT_SUCCESS(rc))
652 {
653 *pcbWriteProcess = cbWrite;
654 *pcbPostRead = 0;
655 *pcbPreRead = 0;
656 }
657
658 return rc;
659}
660
661/** @copydoc VBOXHDDBACKEND::pfnFlush */
662static int rawFlush(void *pBackendData, PVDIOCTX pIoCtx)
663{
664 int rc = VINF_SUCCESS;
665 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
666
667 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
668 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
669 NULL, NULL);
670
671 return rc;
672}
673
674/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
675static unsigned rawGetVersion(void *pBackendData)
676{
677 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
678 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
679
680 AssertPtr(pImage);
681
682 if (pImage)
683 return 1;
684 else
685 return 0;
686}
687
688/** @copydoc VBOXHDDBACKEND::pfnGetSize */
689static uint32_t rawGetSectorSize(void *pBackendData)
690{
691 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
692 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
693 uint32_t cb = 0;
694
695 AssertPtr(pImage);
696
697 if (pImage && pImage->pStorage)
698 cb = pImage->cbSector;
699
700 LogFlowFunc(("returns %u\n", cb));
701 return cb;
702}
703
704/** @copydoc VBOXHDDBACKEND::pfnGetSize */
705static uint64_t rawGetSize(void *pBackendData)
706{
707 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
708 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
709 uint64_t cb = 0;
710
711 AssertPtr(pImage);
712
713 if (pImage && pImage->pStorage)
714 cb = pImage->cbSize;
715
716 LogFlowFunc(("returns %llu\n", cb));
717 return cb;
718}
719
720/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
721static uint64_t rawGetFileSize(void *pBackendData)
722{
723 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
724 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
725 uint64_t cb = 0;
726
727 AssertPtr(pImage);
728
729 if (pImage)
730 {
731 uint64_t cbFile;
732 if (pImage->pStorage)
733 {
734 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
735 if (RT_SUCCESS(rc))
736 cb += cbFile;
737 }
738 }
739
740 LogFlowFunc(("returns %lld\n", cb));
741 return cb;
742}
743
744/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
745static int rawGetPCHSGeometry(void *pBackendData,
746 PVDGEOMETRY pPCHSGeometry)
747{
748 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
749 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
750 int rc;
751
752 AssertPtr(pImage);
753
754 if (pImage)
755 {
756 if (pImage->PCHSGeometry.cCylinders)
757 {
758 *pPCHSGeometry = pImage->PCHSGeometry;
759 rc = VINF_SUCCESS;
760 }
761 else
762 rc = VERR_VD_GEOMETRY_NOT_SET;
763 }
764 else
765 rc = VERR_VD_NOT_OPENED;
766
767 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
768 return rc;
769}
770
771/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
772static int rawSetPCHSGeometry(void *pBackendData,
773 PCVDGEOMETRY pPCHSGeometry)
774{
775 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
776 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
777 int rc;
778
779 AssertPtr(pImage);
780
781 if (pImage)
782 {
783 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
784 {
785 rc = VERR_VD_IMAGE_READ_ONLY;
786 goto out;
787 }
788
789 pImage->PCHSGeometry = *pPCHSGeometry;
790 rc = VINF_SUCCESS;
791 }
792 else
793 rc = VERR_VD_NOT_OPENED;
794
795out:
796 LogFlowFunc(("returns %Rrc\n", rc));
797 return rc;
798}
799
800/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
801static int rawGetLCHSGeometry(void *pBackendData,
802 PVDGEOMETRY pLCHSGeometry)
803{
804 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
805 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
806 int rc;
807
808 AssertPtr(pImage);
809
810 if (pImage)
811 {
812 if (pImage->LCHSGeometry.cCylinders)
813 {
814 *pLCHSGeometry = pImage->LCHSGeometry;
815 rc = VINF_SUCCESS;
816 }
817 else
818 rc = VERR_VD_GEOMETRY_NOT_SET;
819 }
820 else
821 rc = VERR_VD_NOT_OPENED;
822
823 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
824 return rc;
825}
826
827/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
828static int rawSetLCHSGeometry(void *pBackendData,
829 PCVDGEOMETRY pLCHSGeometry)
830{
831 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
832 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
833 int rc;
834
835 AssertPtr(pImage);
836
837 if (pImage)
838 {
839 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
840 {
841 rc = VERR_VD_IMAGE_READ_ONLY;
842 goto out;
843 }
844
845 pImage->LCHSGeometry = *pLCHSGeometry;
846 rc = VINF_SUCCESS;
847 }
848 else
849 rc = VERR_VD_NOT_OPENED;
850
851out:
852 LogFlowFunc(("returns %Rrc\n", rc));
853 return rc;
854}
855
856/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
857static unsigned rawGetImageFlags(void *pBackendData)
858{
859 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
860 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
861 unsigned uImageFlags;
862
863 AssertPtr(pImage);
864
865 if (pImage)
866 uImageFlags = pImage->uImageFlags;
867 else
868 uImageFlags = 0;
869
870 LogFlowFunc(("returns %#x\n", uImageFlags));
871 return uImageFlags;
872}
873
874/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
875static unsigned rawGetOpenFlags(void *pBackendData)
876{
877 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
878 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
879 unsigned uOpenFlags;
880
881 AssertPtr(pImage);
882
883 if (pImage)
884 uOpenFlags = pImage->uOpenFlags;
885 else
886 uOpenFlags = 0;
887
888 LogFlowFunc(("returns %#x\n", uOpenFlags));
889 return uOpenFlags;
890}
891
892/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
893static int rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
894{
895 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
896 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
897 int rc;
898
899 /* Image must be opened and the new flags must be valid. */
900 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
901 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
902 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
903 {
904 rc = VERR_INVALID_PARAMETER;
905 goto out;
906 }
907
908 /* Implement this operation via reopening the image. */
909 rc = rawFreeImage(pImage, false);
910 if (RT_FAILURE(rc))
911 goto out;
912 rc = rawOpenImage(pImage, uOpenFlags);
913
914out:
915 LogFlowFunc(("returns %Rrc\n", rc));
916 return rc;
917}
918
919/** @copydoc VBOXHDDBACKEND::pfnGetComment */
920static int rawGetComment(void *pBackendData, char *pszComment,
921 size_t cbComment)
922{
923 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
924 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
925 int rc;
926
927 AssertPtr(pImage);
928
929 if (pImage)
930 rc = VERR_NOT_SUPPORTED;
931 else
932 rc = VERR_VD_NOT_OPENED;
933
934 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
935 return rc;
936}
937
938/** @copydoc VBOXHDDBACKEND::pfnSetComment */
939static int rawSetComment(void *pBackendData, const char *pszComment)
940{
941 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
942 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
943 int rc;
944
945 AssertPtr(pImage);
946
947 if (pImage)
948 {
949 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
950 rc = VERR_VD_IMAGE_READ_ONLY;
951 else
952 rc = VERR_NOT_SUPPORTED;
953 }
954 else
955 rc = VERR_VD_NOT_OPENED;
956
957 LogFlowFunc(("returns %Rrc\n", rc));
958 return rc;
959}
960
961/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
962static int rawGetUuid(void *pBackendData, PRTUUID pUuid)
963{
964 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
965 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
966 int rc;
967
968 AssertPtr(pImage);
969
970 if (pImage)
971 rc = VERR_NOT_SUPPORTED;
972 else
973 rc = VERR_VD_NOT_OPENED;
974
975 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
976 return rc;
977}
978
979/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
980static int rawSetUuid(void *pBackendData, PCRTUUID pUuid)
981{
982 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
983 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
984 int rc;
985
986 LogFlowFunc(("%RTuuid\n", pUuid));
987 AssertPtr(pImage);
988
989 if (pImage)
990 {
991 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
992 rc = VERR_NOT_SUPPORTED;
993 else
994 rc = VERR_VD_IMAGE_READ_ONLY;
995 }
996 else
997 rc = VERR_VD_NOT_OPENED;
998
999 LogFlowFunc(("returns %Rrc\n", rc));
1000 return rc;
1001}
1002
1003/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1004static int rawGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1005{
1006 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1007 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1008 int rc;
1009
1010 AssertPtr(pImage);
1011
1012 if (pImage)
1013 rc = VERR_NOT_SUPPORTED;
1014 else
1015 rc = VERR_VD_NOT_OPENED;
1016
1017 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1018 return rc;
1019}
1020
1021/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1022static int rawSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1023{
1024 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1025 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1026 int rc;
1027
1028 AssertPtr(pImage);
1029
1030 if (pImage)
1031 {
1032 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1033 rc = VERR_NOT_SUPPORTED;
1034 else
1035 rc = VERR_VD_IMAGE_READ_ONLY;
1036 }
1037 else
1038 rc = VERR_VD_NOT_OPENED;
1039
1040 LogFlowFunc(("returns %Rrc\n", rc));
1041 return rc;
1042}
1043
1044/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1045static int rawGetParentUuid(void *pBackendData, PRTUUID pUuid)
1046{
1047 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1048 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1049 int rc;
1050
1051 AssertPtr(pImage);
1052
1053 if (pImage)
1054 rc = VERR_NOT_SUPPORTED;
1055 else
1056 rc = VERR_VD_NOT_OPENED;
1057
1058 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1059 return rc;
1060}
1061
1062/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1063static int rawSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1064{
1065 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1066 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1067 int rc;
1068
1069 AssertPtr(pImage);
1070
1071 if (pImage)
1072 {
1073 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1074 rc = VERR_NOT_SUPPORTED;
1075 else
1076 rc = VERR_VD_IMAGE_READ_ONLY;
1077 }
1078 else
1079 rc = VERR_VD_NOT_OPENED;
1080
1081 LogFlowFunc(("returns %Rrc\n", rc));
1082 return rc;
1083}
1084
1085/** @copydoc VBOXHDDBACKEND::pfnGetParentModificationUuid */
1086static int rawGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1087{
1088 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1089 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1090 int rc;
1091
1092 AssertPtr(pImage);
1093
1094 if (pImage)
1095 rc = VERR_NOT_SUPPORTED;
1096 else
1097 rc = VERR_VD_NOT_OPENED;
1098
1099 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1100 return rc;
1101}
1102
1103/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1104static int rawSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1105{
1106 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1107 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1108 int rc;
1109
1110 AssertPtr(pImage);
1111
1112 if (pImage)
1113 {
1114 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1115 rc = VERR_NOT_SUPPORTED;
1116 else
1117 rc = VERR_VD_IMAGE_READ_ONLY;
1118 }
1119 else
1120 rc = VERR_VD_NOT_OPENED;
1121
1122 LogFlowFunc(("returns %Rrc\n", rc));
1123 return rc;
1124}
1125
1126/** @copydoc VBOXHDDBACKEND::pfnDump */
1127static void rawDump(void *pBackendData)
1128{
1129 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1130
1131 AssertPtr(pImage);
1132 if (pImage)
1133 {
1134 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
1135 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1136 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
1137 pImage->cbSize / 512);
1138 }
1139}
1140
1141
1142
1143const VBOXHDDBACKEND g_RawBackend =
1144{
1145 /* pszBackendName */
1146 "RAW",
1147 /* cbSize */
1148 sizeof(VBOXHDDBACKEND),
1149 /* uBackendCaps */
1150 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1151 /* paFileExtensions */
1152 s_aRawFileExtensions,
1153 /* paConfigInfo */
1154 NULL,
1155 /* pfnCheckIfValid */
1156 rawCheckIfValid,
1157 /* pfnOpen */
1158 rawOpen,
1159 /* pfnCreate */
1160 rawCreate,
1161 /* pfnRename */
1162 rawRename,
1163 /* pfnClose */
1164 rawClose,
1165 /* pfnRead */
1166 rawRead,
1167 /* pfnWrite */
1168 rawWrite,
1169 /* pfnFlush */
1170 rawFlush,
1171 /* pfnDiscard */
1172 NULL,
1173 /* pfnGetVersion */
1174 rawGetVersion,
1175 /* pfnGetSectorSize */
1176 rawGetSectorSize,
1177 /* pfnGetSize */
1178 rawGetSize,
1179 /* pfnGetFileSize */
1180 rawGetFileSize,
1181 /* pfnGetPCHSGeometry */
1182 rawGetPCHSGeometry,
1183 /* pfnSetPCHSGeometry */
1184 rawSetPCHSGeometry,
1185 /* pfnGetLCHSGeometry */
1186 rawGetLCHSGeometry,
1187 /* pfnSetLCHSGeometry */
1188 rawSetLCHSGeometry,
1189 /* pfnGetImageFlags */
1190 rawGetImageFlags,
1191 /* pfnGetOpenFlags */
1192 rawGetOpenFlags,
1193 /* pfnSetOpenFlags */
1194 rawSetOpenFlags,
1195 /* pfnGetComment */
1196 rawGetComment,
1197 /* pfnSetComment */
1198 rawSetComment,
1199 /* pfnGetUuid */
1200 rawGetUuid,
1201 /* pfnSetUuid */
1202 rawSetUuid,
1203 /* pfnGetModificationUuid */
1204 rawGetModificationUuid,
1205 /* pfnSetModificationUuid */
1206 rawSetModificationUuid,
1207 /* pfnGetParentUuid */
1208 rawGetParentUuid,
1209 /* pfnSetParentUuid */
1210 rawSetParentUuid,
1211 /* pfnGetParentModificationUuid */
1212 rawGetParentModificationUuid,
1213 /* pfnSetParentModificationUuid */
1214 rawSetParentModificationUuid,
1215 /* pfnDump */
1216 rawDump,
1217 /* pfnGetTimeStamp */
1218 NULL,
1219 /* pfnGetParentTimeStamp */
1220 NULL,
1221 /* pfnSetParentTimeStamp */
1222 NULL,
1223 /* pfnGetParentFilename */
1224 NULL,
1225 /* pfnSetParentFilename */
1226 NULL,
1227 /* pfnComposeLocation */
1228 genericFileComposeLocation,
1229 /* pfnComposeName */
1230 genericFileComposeName,
1231 /* pfnCompact */
1232 NULL,
1233 /* pfnResize */
1234 NULL,
1235 /* pfnRepair */
1236 NULL,
1237 /* pfnTraverseMetadata */
1238 NULL
1239};
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