VirtualBox

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

Last change on this file since 63001 was 62747, checked in by vboxsync, 8 years ago

Storage: warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.4 KB
Line 
1/* $Id: RAW.cpp 62747 2016-07-30 16:01:43Z vboxsync $ */
2/** @file
3 * RawHDDCore - Raw Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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 RT_NOREF1(pszComment);
237 int rc;
238 RTFOFF cbFree = 0;
239 int32_t fOpen;
240
241 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
242
243 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
244
245 pImage->uImageFlags = uImageFlags;
246 pImage->fCreate = true;
247 pImage->PCHSGeometry = *pPCHSGeometry;
248 pImage->LCHSGeometry = *pLCHSGeometry;
249
250 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
251 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
252 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
253
254 if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
255 {
256 rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
257 goto out;
258 }
259
260 /* Create image file. */
261 fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
262 if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
263 fOpen &= ~RTFILE_O_READ;
264 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
265 if (RT_FAILURE(rc))
266 {
267 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
268 goto out;
269 }
270
271 if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
272 {
273 /* Check the free space on the disk and leave early if there is not
274 * sufficient space available. */
275 rc = vdIfIoIntFileGetFreeSpace(pImage->pIfIo, pImage->pszFilename, &cbFree);
276 if (RT_SUCCESS(rc) /* ignore errors */ && ((uint64_t)cbFree < cbSize))
277 {
278 rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
279 goto out;
280 }
281
282 /* Allocate & commit whole file if fixed image, it must be more
283 * effective than expanding file by write operations. */
284 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pImage->pStorage, cbSize,
285 0 /* fFlags */, pfnProgress, pvUser, uPercentStart, uPercentSpan);
286 }
287
288 if (RT_SUCCESS(rc) && pfnProgress)
289 pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
290
291 pImage->cbSize = cbSize;
292
293 rc = rawFlushImage(pImage);
294
295out:
296
297 if (RT_SUCCESS(rc) && pfnProgress)
298 pfnProgress(pvUser, uPercentStart + uPercentSpan);
299
300 if (RT_FAILURE(rc))
301 rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
302 return rc;
303}
304
305
306/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
307static DECLCALLBACK(int) rawCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
308 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
309{
310 RT_NOREF1(pVDIfsDisk);
311 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
312 PVDIOSTORAGE pStorage = NULL;
313 uint64_t cbFile;
314 int rc = VINF_SUCCESS;
315 char *pszSuffix = NULL;
316
317 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
318 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
319
320 if ( !VALID_PTR(pszFilename)
321 || !*pszFilename)
322 {
323 rc = VERR_INVALID_PARAMETER;
324 goto out;
325 }
326
327 pszSuffix = RTPathSuffix(pszFilename);
328
329 /*
330 * Open the file and read the footer.
331 */
332 rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
333 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
334 false /* fCreate */),
335 &pStorage);
336 if (RT_SUCCESS(rc))
337 {
338 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
339
340 /* Try to guess the image type based on the extension. */
341 if ( RT_SUCCESS(rc)
342 && pszSuffix)
343 {
344 if ( !RTStrICmp(pszSuffix, ".iso")
345 || !RTStrICmp(pszSuffix, ".cdr")) /* DVD images. */
346 {
347 /* Note that there are ISO images smaller than 1 MB; it is impossible to distinguish
348 * between raw floppy and CD images based on their size (and cannot be reliably done
349 * based on contents, either).
350 */
351 if (cbFile % 2048)
352 rc = VERR_VD_RAW_SIZE_MODULO_2048;
353 else if (cbFile <= 32768)
354 rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL;
355 else
356 {
357 *penmType = VDTYPE_DVD;
358 rc = VINF_SUCCESS;
359 }
360 }
361 else if ( !RTStrICmp(pszSuffix, ".img")
362 || !RTStrICmp(pszSuffix, ".ima")
363 || !RTStrICmp(pszSuffix, ".dsk")
364 || !RTStrICmp(pszSuffix, ".flp")
365 || !RTStrICmp(pszSuffix, ".vfd")) /* Floppy images */
366 {
367 if (cbFile % 512)
368 rc = VERR_VD_RAW_SIZE_MODULO_512;
369 else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE)
370 rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG;
371 else
372 {
373 *penmType = VDTYPE_FLOPPY;
374 rc = VINF_SUCCESS;
375 }
376 }
377 else
378 rc = VERR_VD_RAW_INVALID_HEADER;
379 }
380 else
381 rc = VERR_VD_RAW_INVALID_HEADER;
382 }
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 RT_NOREF1(pUuid);
458 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",
459 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
460 int rc;
461 PRAWIMAGE pImage;
462
463 PFNVDPROGRESS pfnProgress = NULL;
464 void *pvUser = NULL;
465 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
466 if (pIfProgress)
467 {
468 pfnProgress = pIfProgress->pfnProgress;
469 pvUser = pIfProgress->Core.pvUser;
470 }
471
472 /* Check the VD container type. Yes, hard disk must be allowed, otherwise
473 * various tools using this backend for hard disk images will fail. */
474 if (enmType != VDTYPE_HDD && enmType != VDTYPE_DVD && enmType != VDTYPE_FLOPPY)
475 {
476 rc = VERR_VD_INVALID_TYPE;
477 goto out;
478 }
479
480 /* Check open flags. All valid flags are supported. */
481 if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
482 {
483 rc = VERR_INVALID_PARAMETER;
484 goto out;
485 }
486
487 /* Check remaining arguments. */
488 if ( !VALID_PTR(pszFilename)
489 || !*pszFilename
490 || !VALID_PTR(pPCHSGeometry)
491 || !VALID_PTR(pLCHSGeometry))
492 {
493 rc = VERR_INVALID_PARAMETER;
494 goto out;
495 }
496
497 pImage = (PRAWIMAGE)RTMemAllocZ(sizeof(RAWIMAGE));
498 if (!pImage)
499 {
500 rc = VERR_NO_MEMORY;
501 goto out;
502 }
503 pImage->pszFilename = pszFilename;
504 pImage->pStorage = NULL;
505 pImage->pVDIfsDisk = pVDIfsDisk;
506 pImage->pVDIfsImage = pVDIfsImage;
507
508 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
509 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
510 pfnProgress, pvUser, uPercentStart, uPercentSpan);
511 if (RT_SUCCESS(rc))
512 {
513 /* So far the image is opened in read/write mode. Make sure the
514 * image is opened in read-only mode if the caller requested that. */
515 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
516 {
517 rawFreeImage(pImage, false);
518 rc = rawOpenImage(pImage, uOpenFlags);
519 if (RT_FAILURE(rc))
520 {
521 RTMemFree(pImage);
522 goto out;
523 }
524 }
525 *ppBackendData = pImage;
526 }
527 else
528 RTMemFree(pImage);
529
530out:
531 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
532 return rc;
533}
534
535/** @copydoc VBOXHDDBACKEND::pfnRename */
536static DECLCALLBACK(int) rawRename(void *pBackendData, const char *pszFilename)
537{
538 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
539 int rc = VINF_SUCCESS;
540 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
541
542 /* Check arguments. */
543 if ( !pImage
544 || !pszFilename
545 || !*pszFilename)
546 {
547 rc = VERR_INVALID_PARAMETER;
548 goto out;
549 }
550
551 /* Close the image. */
552 rc = rawFreeImage(pImage, false);
553 if (RT_FAILURE(rc))
554 goto out;
555
556 /* Rename the file. */
557 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
558 if (RT_FAILURE(rc))
559 {
560 /* The move failed, try to reopen the original image. */
561 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
562 if (RT_FAILURE(rc2))
563 rc = rc2;
564
565 goto out;
566 }
567
568 /* Update pImage with the new information. */
569 pImage->pszFilename = pszFilename;
570
571 /* Open the old image with new name. */
572 rc = rawOpenImage(pImage, pImage->uOpenFlags);
573 if (RT_FAILURE(rc))
574 goto out;
575
576out:
577 LogFlowFunc(("returns %Rrc\n", rc));
578 return rc;
579}
580
581/** @copydoc VBOXHDDBACKEND::pfnClose */
582static DECLCALLBACK(int) rawClose(void *pBackendData, bool fDelete)
583{
584 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
585 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
586 int rc;
587
588 rc = rawFreeImage(pImage, fDelete);
589 RTMemFree(pImage);
590
591 LogFlowFunc(("returns %Rrc\n", rc));
592 return rc;
593}
594
595/** @copydoc VBOXHDDBACKEND::pfnRead */
596static DECLCALLBACK(int) rawRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
597 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
598{
599 int rc = VINF_SUCCESS;
600 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
601
602 /* For sequential access do not allow to go back. */
603 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
604 && uOffset < pImage->offAccess)
605 {
606 *pcbActuallyRead = 0;
607 return VERR_INVALID_PARAMETER;
608 }
609
610 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
611 pIoCtx, cbRead);
612 if (RT_SUCCESS(rc))
613 {
614 *pcbActuallyRead = cbRead;
615 pImage->offAccess = uOffset + cbRead;
616 }
617
618 return rc;
619}
620
621/** @copydoc VBOXHDDBACKEND::pfnWrite */
622static DECLCALLBACK(int) rawWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
623 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
624 size_t *pcbPostRead, unsigned fWrite)
625{
626 RT_NOREF1(fWrite);
627 int rc = VINF_SUCCESS;
628 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
629
630 /* For sequential access do not allow to go back. */
631 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
632 && uOffset < pImage->offAccess)
633 {
634 *pcbWriteProcess = 0;
635 *pcbPostRead = 0;
636 *pcbPreRead = 0;
637 return VERR_INVALID_PARAMETER;
638 }
639
640 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
641 pIoCtx, cbWrite, NULL, NULL);
642 if (RT_SUCCESS(rc))
643 {
644 *pcbWriteProcess = cbWrite;
645 *pcbPostRead = 0;
646 *pcbPreRead = 0;
647 pImage->offAccess = uOffset + cbWrite;
648 }
649
650 return rc;
651}
652
653/** @copydoc VBOXHDDBACKEND::pfnFlush */
654static DECLCALLBACK(int) rawFlush(void *pBackendData, PVDIOCTX pIoCtx)
655{
656 int rc = VINF_SUCCESS;
657 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
658
659 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
660 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
661 NULL, NULL);
662
663 return rc;
664}
665
666/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
667static DECLCALLBACK(unsigned) rawGetVersion(void *pBackendData)
668{
669 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
670 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
671
672 AssertPtr(pImage);
673
674 if (pImage)
675 return 1;
676 else
677 return 0;
678}
679
680/** @copydoc VBOXHDDBACKEND::pfnGetSize */
681static DECLCALLBACK(uint32_t) rawGetSectorSize(void *pBackendData)
682{
683 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
684 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
685 uint32_t cb = 0;
686
687 AssertPtr(pImage);
688
689 if (pImage && pImage->pStorage)
690 cb = pImage->cbSector;
691
692 LogFlowFunc(("returns %u\n", cb));
693 return cb;
694}
695
696/** @copydoc VBOXHDDBACKEND::pfnGetSize */
697static DECLCALLBACK(uint64_t) rawGetSize(void *pBackendData)
698{
699 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
700 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
701 uint64_t cb = 0;
702
703 AssertPtr(pImage);
704
705 if (pImage && pImage->pStorage)
706 cb = pImage->cbSize;
707
708 LogFlowFunc(("returns %llu\n", cb));
709 return cb;
710}
711
712/** @copydoc VBOXHDDBACKEND::pfnGetFileSize */
713static DECLCALLBACK(uint64_t) rawGetFileSize(void *pBackendData)
714{
715 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
716 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
717 uint64_t cb = 0;
718
719 AssertPtr(pImage);
720
721 if (pImage)
722 {
723 uint64_t cbFile;
724 if (pImage->pStorage)
725 {
726 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
727 if (RT_SUCCESS(rc))
728 cb += cbFile;
729 }
730 }
731
732 LogFlowFunc(("returns %lld\n", cb));
733 return cb;
734}
735
736/** @copydoc VBOXHDDBACKEND::pfnGetPCHSGeometry */
737static DECLCALLBACK(int) rawGetPCHSGeometry(void *pBackendData,
738 PVDGEOMETRY pPCHSGeometry)
739{
740 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
741 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
742 int rc;
743
744 AssertPtr(pImage);
745
746 if (pImage)
747 {
748 if (pImage->PCHSGeometry.cCylinders)
749 {
750 *pPCHSGeometry = pImage->PCHSGeometry;
751 rc = VINF_SUCCESS;
752 }
753 else
754 rc = VERR_VD_GEOMETRY_NOT_SET;
755 }
756 else
757 rc = VERR_VD_NOT_OPENED;
758
759 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
760 return rc;
761}
762
763/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
764static DECLCALLBACK(int) rawSetPCHSGeometry(void *pBackendData,
765 PCVDGEOMETRY pPCHSGeometry)
766{
767 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
768 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
769 int rc;
770
771 AssertPtr(pImage);
772
773 if (pImage)
774 {
775 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
776 {
777 rc = VERR_VD_IMAGE_READ_ONLY;
778 goto out;
779 }
780
781 pImage->PCHSGeometry = *pPCHSGeometry;
782 rc = VINF_SUCCESS;
783 }
784 else
785 rc = VERR_VD_NOT_OPENED;
786
787out:
788 LogFlowFunc(("returns %Rrc\n", rc));
789 return rc;
790}
791
792/** @copydoc VBOXHDDBACKEND::pfnGetLCHSGeometry */
793static DECLCALLBACK(int) rawGetLCHSGeometry(void *pBackendData,
794 PVDGEOMETRY pLCHSGeometry)
795{
796 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
797 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
798 int rc;
799
800 AssertPtr(pImage);
801
802 if (pImage)
803 {
804 if (pImage->LCHSGeometry.cCylinders)
805 {
806 *pLCHSGeometry = pImage->LCHSGeometry;
807 rc = VINF_SUCCESS;
808 }
809 else
810 rc = VERR_VD_GEOMETRY_NOT_SET;
811 }
812 else
813 rc = VERR_VD_NOT_OPENED;
814
815 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
816 return rc;
817}
818
819/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
820static DECLCALLBACK(int) rawSetLCHSGeometry(void *pBackendData,
821 PCVDGEOMETRY pLCHSGeometry)
822{
823 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
824 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
825 int rc;
826
827 AssertPtr(pImage);
828
829 if (pImage)
830 {
831 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
832 {
833 rc = VERR_VD_IMAGE_READ_ONLY;
834 goto out;
835 }
836
837 pImage->LCHSGeometry = *pLCHSGeometry;
838 rc = VINF_SUCCESS;
839 }
840 else
841 rc = VERR_VD_NOT_OPENED;
842
843out:
844 LogFlowFunc(("returns %Rrc\n", rc));
845 return rc;
846}
847
848/** @copydoc VBOXHDDBACKEND::pfnGetImageFlags */
849static DECLCALLBACK(unsigned) rawGetImageFlags(void *pBackendData)
850{
851 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
852 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
853 unsigned uImageFlags;
854
855 AssertPtr(pImage);
856
857 if (pImage)
858 uImageFlags = pImage->uImageFlags;
859 else
860 uImageFlags = 0;
861
862 LogFlowFunc(("returns %#x\n", uImageFlags));
863 return uImageFlags;
864}
865
866/** @copydoc VBOXHDDBACKEND::pfnGetOpenFlags */
867static DECLCALLBACK(unsigned) rawGetOpenFlags(void *pBackendData)
868{
869 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
870 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
871 unsigned uOpenFlags;
872
873 AssertPtr(pImage);
874
875 if (pImage)
876 uOpenFlags = pImage->uOpenFlags;
877 else
878 uOpenFlags = 0;
879
880 LogFlowFunc(("returns %#x\n", uOpenFlags));
881 return uOpenFlags;
882}
883
884/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
885static DECLCALLBACK(int) rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
886{
887 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
888 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
889 int rc;
890
891 /* Image must be opened and the new flags must be valid. */
892 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
893 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
894 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
895 {
896 rc = VERR_INVALID_PARAMETER;
897 goto out;
898 }
899
900 /* Implement this operation via reopening the image. */
901 rc = rawFreeImage(pImage, false);
902 if (RT_FAILURE(rc))
903 goto out;
904 rc = rawOpenImage(pImage, uOpenFlags);
905
906out:
907 LogFlowFunc(("returns %Rrc\n", rc));
908 return rc;
909}
910
911/** @copydoc VBOXHDDBACKEND::pfnGetComment */
912static DECLCALLBACK(int) rawGetComment(void *pBackendData, char *pszComment,
913 size_t cbComment)
914{
915 RT_NOREF2(pszComment, cbComment);
916 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
917 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
918 int rc;
919
920 AssertPtr(pImage);
921
922 if (pImage)
923 rc = VERR_NOT_SUPPORTED;
924 else
925 rc = VERR_VD_NOT_OPENED;
926
927 LogFlowFunc(("returns %Rrc comment='%s'\n", rc, pszComment));
928 return rc;
929}
930
931/** @copydoc VBOXHDDBACKEND::pfnSetComment */
932static DECLCALLBACK(int) rawSetComment(void *pBackendData, const char *pszComment)
933{
934 RT_NOREF1(pszComment);
935 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
936 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
937 int rc;
938
939 AssertPtr(pImage);
940
941 if (pImage)
942 {
943 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
944 rc = VERR_VD_IMAGE_READ_ONLY;
945 else
946 rc = VERR_NOT_SUPPORTED;
947 }
948 else
949 rc = VERR_VD_NOT_OPENED;
950
951 LogFlowFunc(("returns %Rrc\n", rc));
952 return rc;
953}
954
955/** @copydoc VBOXHDDBACKEND::pfnGetUuid */
956static DECLCALLBACK(int) rawGetUuid(void *pBackendData, PRTUUID pUuid)
957{
958 RT_NOREF1(pUuid);
959 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
960 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
961 int rc;
962
963 AssertPtr(pImage);
964
965 if (pImage)
966 rc = VERR_NOT_SUPPORTED;
967 else
968 rc = VERR_VD_NOT_OPENED;
969
970 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
971 return rc;
972}
973
974/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
975static DECLCALLBACK(int) rawSetUuid(void *pBackendData, PCRTUUID pUuid)
976{
977 RT_NOREF1(pUuid);
978 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
979 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
980 int rc;
981
982 LogFlowFunc(("%RTuuid\n", pUuid));
983 AssertPtr(pImage);
984
985 if (pImage)
986 {
987 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
988 rc = VERR_NOT_SUPPORTED;
989 else
990 rc = VERR_VD_IMAGE_READ_ONLY;
991 }
992 else
993 rc = VERR_VD_NOT_OPENED;
994
995 LogFlowFunc(("returns %Rrc\n", rc));
996 return rc;
997}
998
999/** @copydoc VBOXHDDBACKEND::pfnGetModificationUuid */
1000static DECLCALLBACK(int) rawGetModificationUuid(void *pBackendData, PRTUUID pUuid)
1001{
1002 RT_NOREF1(pUuid);
1003 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1004 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1005 int rc;
1006
1007 AssertPtr(pImage);
1008
1009 if (pImage)
1010 rc = VERR_NOT_SUPPORTED;
1011 else
1012 rc = VERR_VD_NOT_OPENED;
1013
1014 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1015 return rc;
1016}
1017
1018/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
1019static DECLCALLBACK(int) rawSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
1020{
1021 RT_NOREF1(pUuid);
1022 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1023 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1024 int rc;
1025
1026 AssertPtr(pImage);
1027
1028 if (pImage)
1029 {
1030 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1031 rc = VERR_NOT_SUPPORTED;
1032 else
1033 rc = VERR_VD_IMAGE_READ_ONLY;
1034 }
1035 else
1036 rc = VERR_VD_NOT_OPENED;
1037
1038 LogFlowFunc(("returns %Rrc\n", rc));
1039 return rc;
1040}
1041
1042/** @copydoc VBOXHDDBACKEND::pfnGetParentUuid */
1043static DECLCALLBACK(int) rawGetParentUuid(void *pBackendData, PRTUUID pUuid)
1044{
1045 RT_NOREF1(pUuid);
1046 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1047 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1048 int rc;
1049
1050 AssertPtr(pImage);
1051
1052 if (pImage)
1053 rc = VERR_NOT_SUPPORTED;
1054 else
1055 rc = VERR_VD_NOT_OPENED;
1056
1057 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1058 return rc;
1059}
1060
1061/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
1062static DECLCALLBACK(int) rawSetParentUuid(void *pBackendData, PCRTUUID pUuid)
1063{
1064 RT_NOREF1(pUuid);
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 DECLCALLBACK(int) rawGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
1087{
1088 RT_NOREF1(pUuid);
1089 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
1090 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1091 int rc;
1092
1093 AssertPtr(pImage);
1094
1095 if (pImage)
1096 rc = VERR_NOT_SUPPORTED;
1097 else
1098 rc = VERR_VD_NOT_OPENED;
1099
1100 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
1101 return rc;
1102}
1103
1104/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
1105static DECLCALLBACK(int) rawSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
1106{
1107 RT_NOREF1(pUuid);
1108 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
1109 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1110 int rc;
1111
1112 AssertPtr(pImage);
1113
1114 if (pImage)
1115 {
1116 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
1117 rc = VERR_NOT_SUPPORTED;
1118 else
1119 rc = VERR_VD_IMAGE_READ_ONLY;
1120 }
1121 else
1122 rc = VERR_VD_NOT_OPENED;
1123
1124 LogFlowFunc(("returns %Rrc\n", rc));
1125 return rc;
1126}
1127
1128/** @copydoc VBOXHDDBACKEND::pfnDump */
1129static DECLCALLBACK(void) rawDump(void *pBackendData)
1130{
1131 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1132
1133 AssertPtr(pImage);
1134 if (pImage)
1135 {
1136 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
1137 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1138 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
1139 pImage->cbSize / 512);
1140 }
1141}
1142
1143
1144
1145const VBOXHDDBACKEND g_RawBackend =
1146{
1147 /* pszBackendName */
1148 "RAW",
1149 /* cbSize */
1150 sizeof(VBOXHDDBACKEND),
1151 /* uBackendCaps */
1152 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1153 /* paFileExtensions */
1154 s_aRawFileExtensions,
1155 /* paConfigInfo */
1156 NULL,
1157 /* pfnCheckIfValid */
1158 rawCheckIfValid,
1159 /* pfnOpen */
1160 rawOpen,
1161 /* pfnCreate */
1162 rawCreate,
1163 /* pfnRename */
1164 rawRename,
1165 /* pfnClose */
1166 rawClose,
1167 /* pfnRead */
1168 rawRead,
1169 /* pfnWrite */
1170 rawWrite,
1171 /* pfnFlush */
1172 rawFlush,
1173 /* pfnDiscard */
1174 NULL,
1175 /* pfnGetVersion */
1176 rawGetVersion,
1177 /* pfnGetSectorSize */
1178 rawGetSectorSize,
1179 /* pfnGetSize */
1180 rawGetSize,
1181 /* pfnGetFileSize */
1182 rawGetFileSize,
1183 /* pfnGetPCHSGeometry */
1184 rawGetPCHSGeometry,
1185 /* pfnSetPCHSGeometry */
1186 rawSetPCHSGeometry,
1187 /* pfnGetLCHSGeometry */
1188 rawGetLCHSGeometry,
1189 /* pfnSetLCHSGeometry */
1190 rawSetLCHSGeometry,
1191 /* pfnGetImageFlags */
1192 rawGetImageFlags,
1193 /* pfnGetOpenFlags */
1194 rawGetOpenFlags,
1195 /* pfnSetOpenFlags */
1196 rawSetOpenFlags,
1197 /* pfnGetComment */
1198 rawGetComment,
1199 /* pfnSetComment */
1200 rawSetComment,
1201 /* pfnGetUuid */
1202 rawGetUuid,
1203 /* pfnSetUuid */
1204 rawSetUuid,
1205 /* pfnGetModificationUuid */
1206 rawGetModificationUuid,
1207 /* pfnSetModificationUuid */
1208 rawSetModificationUuid,
1209 /* pfnGetParentUuid */
1210 rawGetParentUuid,
1211 /* pfnSetParentUuid */
1212 rawSetParentUuid,
1213 /* pfnGetParentModificationUuid */
1214 rawGetParentModificationUuid,
1215 /* pfnSetParentModificationUuid */
1216 rawSetParentModificationUuid,
1217 /* pfnDump */
1218 rawDump,
1219 /* pfnGetTimestamp */
1220 NULL,
1221 /* pfnGetParentTimestamp */
1222 NULL,
1223 /* pfnSetParentTimestamp */
1224 NULL,
1225 /* pfnGetParentFilename */
1226 NULL,
1227 /* pfnSetParentFilename */
1228 NULL,
1229 /* pfnComposeLocation */
1230 genericFileComposeLocation,
1231 /* pfnComposeName */
1232 genericFileComposeName,
1233 /* pfnCompact */
1234 NULL,
1235 /* pfnResize */
1236 NULL,
1237 /* pfnRepair */
1238 NULL,
1239 /* pfnTraverseMetadata */
1240 NULL
1241};
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