VirtualBox

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

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

Another build fix

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

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