VirtualBox

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

Last change on this file since 46852 was 46613, checked in by vboxsync, 11 years ago

Storage: Propagate errors when closing a file but free everything nevertheless (see @bugref{6791})

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