VirtualBox

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

Last change on this file since 69496 was 69496, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 KB
Line 
1/* $Id: RAW.cpp 69496 2017-10-28 14:55:58Z vboxsync $ */
2/** @file
3 * RawHDDCore - Raw Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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#include "VDBackendsInline.h"
33
34
35/*********************************************************************************************************************************
36* Constants And Macros, Structures and Typedefs *
37*********************************************************************************************************************************/
38
39/**
40 * Raw image data structure.
41 */
42typedef struct RAWIMAGE
43{
44 /** Image name. */
45 const char *pszFilename;
46 /** Storage handle. */
47 PVDIOSTORAGE pStorage;
48
49 /** Pointer to the per-disk VD interface list. */
50 PVDINTERFACE pVDIfsDisk;
51 /** Pointer to the per-image VD interface list. */
52 PVDINTERFACE pVDIfsImage;
53 /** Error interface. */
54 PVDINTERFACEERROR pIfError;
55 /** I/O interface. */
56 PVDINTERFACEIOINT pIfIo;
57
58 /** Open flags passed by VBoxHD layer. */
59 unsigned uOpenFlags;
60 /** Image flags defined during creation or determined during open. */
61 unsigned uImageFlags;
62 /** Total size of the image. */
63 uint64_t cbSize;
64 /** Position in the image (only truly used for sequential access). */
65 uint64_t offAccess;
66 /** Flag if this is a newly created image. */
67 bool fCreate;
68 /** Physical geometry of this image. */
69 VDGEOMETRY PCHSGeometry;
70 /** Logical geometry of this image. */
71 VDGEOMETRY LCHSGeometry;
72 /** Sector size of the image. */
73 uint32_t cbSector;
74 /** The static region list. */
75 VDREGIONLIST RegionList;
76} RAWIMAGE, *PRAWIMAGE;
77
78
79/** Size of write operations when filling an image with zeroes. */
80#define RAW_FILL_SIZE (128 * _1K)
81
82/** The maximum reasonable size of a floppy image (big format 2.88MB medium). */
83#define RAW_MAX_FLOPPY_IMG_SIZE (512 * 82 * 48 * 2)
84
85
86/*********************************************************************************************************************************
87* Static Variables *
88*********************************************************************************************************************************/
89
90/** NULL-terminated array of supported file extensions. */
91static const VDFILEEXTENSION s_aRawFileExtensions[] =
92{
93 {"iso", VDTYPE_OPTICAL_DISC},
94 {"cdr", VDTYPE_OPTICAL_DISC},
95 {"img", VDTYPE_FLOPPY},
96 {"ima", VDTYPE_FLOPPY},
97 {"dsk", VDTYPE_FLOPPY},
98 {"flp", VDTYPE_FLOPPY},
99 {"vfd", VDTYPE_FLOPPY},
100 {NULL, VDTYPE_INVALID}
101};
102
103
104/*********************************************************************************************************************************
105* Internal Functions *
106*********************************************************************************************************************************/
107
108/**
109 * Internal. Flush image data to disk.
110 */
111static int rawFlushImage(PRAWIMAGE pImage)
112{
113 int rc = VINF_SUCCESS;
114
115 if ( pImage->pStorage
116 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
117 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
118
119 return rc;
120}
121
122/**
123 * Internal. Free all allocated space for representing an image except pImage,
124 * and optionally delete the image from disk.
125 */
126static int rawFreeImage(PRAWIMAGE pImage, bool fDelete)
127{
128 int rc = VINF_SUCCESS;
129
130 /* Freeing a never allocated image (e.g. because the open failed) is
131 * not signalled as an error. After all nothing bad happens. */
132 if (pImage)
133 {
134 if (pImage->pStorage)
135 {
136 /* No point updating the file that is deleted anyway. */
137 if (!fDelete)
138 {
139 /* For newly created images in sequential mode fill it to
140 * the nominal size. */
141 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
142 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
143 && pImage->fCreate)
144 {
145 /* Fill rest of image with zeroes, a must for sequential
146 * images to reach the nominal size. */
147 uint64_t uOff;
148 void *pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
149 if (RT_LIKELY(pvBuf))
150 {
151 uOff = pImage->offAccess;
152 /* Write data to all image blocks. */
153 while (uOff < pImage->cbSize)
154 {
155 unsigned cbChunk = (unsigned)RT_MIN(pImage->cbSize - uOff,
156 RAW_FILL_SIZE);
157
158 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
159 uOff, pvBuf, cbChunk);
160 if (RT_FAILURE(rc))
161 break;
162
163 uOff += cbChunk;
164 }
165
166 RTMemTmpFree(pvBuf);
167 }
168 else
169 rc = VERR_NO_MEMORY;
170 }
171 rawFlushImage(pImage);
172 }
173
174 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
175 pImage->pStorage = NULL;
176 }
177
178 if (fDelete && pImage->pszFilename)
179 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
180 }
181
182 LogFlowFunc(("returns %Rrc\n", rc));
183 return rc;
184}
185
186/**
187 * Internal: Open an image, constructing all necessary data structures.
188 */
189static int rawOpenImage(PRAWIMAGE pImage, unsigned uOpenFlags)
190{
191 pImage->uOpenFlags = uOpenFlags;
192 pImage->fCreate = false;
193
194 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
195 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
196 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
197
198 /* Open the image. */
199 int rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
200 VDOpenFlagsToFileOpenFlags(uOpenFlags,
201 false /* fCreate */),
202 &pImage->pStorage);
203 if (RT_SUCCESS(rc))
204 {
205 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbSize);
206 if ( RT_SUCCESS(rc)
207 && !(pImage->cbSize % 512))
208 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
209 else if (RT_SUCCESS(rc))
210 rc = VERR_VD_RAW_SIZE_MODULO_512;
211 }
212 /* else: Do NOT signal an appropriate error here, as the VD layer has the
213 * choice of retrying the open if it failed. */
214
215 if (RT_SUCCESS(rc))
216 {
217 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
218 pImage->RegionList.fFlags = 0;
219 pImage->RegionList.cRegions = 1;
220
221 pRegion->offRegion = 0; /* Disk start. */
222 pRegion->cbBlock = pImage->cbSector;
223 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
224 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
225 pRegion->cbData = pImage->cbSector;
226 pRegion->cbMetadata = 0;
227 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
228 }
229 else
230 rawFreeImage(pImage, false);
231 return rc;
232}
233
234/**
235 * Internal: Create a raw image.
236 */
237static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize,
238 unsigned uImageFlags, const char *pszComment,
239 PCVDGEOMETRY pPCHSGeometry,
240 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
241 PVDINTERFACEPROGRESS pIfProgress,
242 unsigned uPercentStart, unsigned uPercentSpan)
243{
244 RT_NOREF1(pszComment);
245 int rc = VINF_SUCCESS;
246
247 pImage->fCreate = true;
248 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
249 pImage->uImageFlags = uImageFlags | VD_IMAGE_FLAGS_FIXED;
250 pImage->PCHSGeometry = *pPCHSGeometry;
251 pImage->LCHSGeometry = *pLCHSGeometry;
252 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
253 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
254 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
255
256 if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_DIFF))
257 {
258 /* Create image file. */
259 uint32_t fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
260 if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
261 fOpen &= ~RTFILE_O_READ;
262 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
263 if (RT_SUCCESS(rc))
264 {
265 if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
266 {
267 RTFOFF cbFree = 0;
268
269 /* Check the free space on the disk and leave early if there is not
270 * sufficient space available. */
271 rc = vdIfIoIntFileGetFreeSpace(pImage->pIfIo, pImage->pszFilename, &cbFree);
272 if (RT_FAILURE(rc) /* ignore errors */ || ((uint64_t)cbFree >= cbSize))
273 {
274 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pImage->pStorage, cbSize, 0 /* fFlags */,
275 pIfProgress, uPercentStart, uPercentSpan);
276 if (RT_SUCCESS(rc))
277 {
278 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 98 / 100);
279
280 pImage->cbSize = cbSize;
281 rc = rawFlushImage(pImage);
282 }
283 }
284 else
285 rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
286 }
287 else
288 {
289 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbSize);
290 if (RT_SUCCESS(rc))
291 pImage->cbSize = cbSize;
292 }
293 }
294 else
295 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
296 }
297 else
298 rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
299
300 if (RT_SUCCESS(rc))
301 {
302 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
303 pImage->RegionList.fFlags = 0;
304 pImage->RegionList.cRegions = 1;
305
306 pRegion->offRegion = 0; /* Disk start. */
307 pRegion->cbBlock = pImage->cbSector;
308 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
309 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
310 pRegion->cbData = pImage->cbSector;
311 pRegion->cbMetadata = 0;
312 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
313
314 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan);
315 }
316
317 if (RT_FAILURE(rc))
318 rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
319 return rc;
320}
321
322
323/** @copydoc VDIMAGEBACKEND::pfnProbe */
324static DECLCALLBACK(int) rawProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
325 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
326{
327 RT_NOREF1(pVDIfsDisk);
328 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
329 PVDIOSTORAGE pStorage = NULL;
330 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
331
332 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
333 AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);
334
335 /*
336 * Open the file and read the footer.
337 */
338 int rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
339 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
340 false /* fCreate */),
341 &pStorage);
342 if (RT_SUCCESS(rc))
343 {
344 uint64_t cbFile;
345 const char *pszSuffix = RTPathSuffix(pszFilename);
346 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
347
348 /* Try to guess the image type based on the extension. */
349 if ( RT_SUCCESS(rc)
350 && pszSuffix)
351 {
352 if ( !RTStrICmp(pszSuffix, ".iso")
353 || !RTStrICmp(pszSuffix, ".cdr")) /* DVD images. */
354 {
355 /* Note that there are ISO images smaller than 1 MB; it is impossible to distinguish
356 * between raw floppy and CD images based on their size (and cannot be reliably done
357 * based on contents, either).
358 */
359 if (cbFile % 2048)
360 rc = VERR_VD_RAW_SIZE_MODULO_2048;
361 else if (cbFile <= 32768)
362 rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL;
363 else
364 {
365 *penmType = VDTYPE_OPTICAL_DISC;
366 rc = VINF_SUCCESS;
367 }
368 }
369 else if ( !RTStrICmp(pszSuffix, ".img")
370 || !RTStrICmp(pszSuffix, ".ima")
371 || !RTStrICmp(pszSuffix, ".dsk")
372 || !RTStrICmp(pszSuffix, ".flp")
373 || !RTStrICmp(pszSuffix, ".vfd")) /* Floppy images */
374 {
375 if (cbFile % 512)
376 rc = VERR_VD_RAW_SIZE_MODULO_512;
377 else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE)
378 rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG;
379 else
380 {
381 *penmType = VDTYPE_FLOPPY;
382 rc = VINF_SUCCESS;
383 }
384 }
385 else
386 rc = VERR_VD_RAW_INVALID_HEADER;
387 }
388 else
389 rc = VERR_VD_RAW_INVALID_HEADER;
390 }
391
392 if (pStorage)
393 vdIfIoIntFileClose(pIfIo, pStorage);
394
395 LogFlowFunc(("returns %Rrc\n", rc));
396 return rc;
397}
398
399/** @copydoc VDIMAGEBACKEND::pfnOpen */
400static DECLCALLBACK(int) rawOpen(const char *pszFilename, unsigned uOpenFlags,
401 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
402 VDTYPE enmType, void **ppBackendData)
403{
404 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
405 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
406 int rc;
407 PRAWIMAGE pImage;
408
409 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
410
411 /* Check open flags. All valid flags are supported. */
412 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
413 AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);
414
415 pImage = (PRAWIMAGE)RTMemAllocZ(RT_UOFFSETOF(RAWIMAGE, RegionList.aRegions[1]));
416 if (RT_LIKELY(pImage))
417 {
418 pImage->pszFilename = pszFilename;
419 pImage->pStorage = NULL;
420 pImage->pVDIfsDisk = pVDIfsDisk;
421 pImage->pVDIfsImage = pVDIfsImage;
422
423 if (enmType == VDTYPE_OPTICAL_DISC)
424 pImage->cbSector = 2048;
425 else
426 pImage->cbSector = 512;
427
428 rc = rawOpenImage(pImage, uOpenFlags);
429 if (RT_SUCCESS(rc))
430 *ppBackendData = pImage;
431 else
432 RTMemFree(pImage);
433 }
434 else
435 rc = VERR_NO_MEMORY;
436
437 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
438 return rc;
439}
440
441/** @copydoc VDIMAGEBACKEND::pfnCreate */
442static DECLCALLBACK(int) rawCreate(const char *pszFilename, uint64_t cbSize,
443 unsigned uImageFlags, const char *pszComment,
444 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
445 PCRTUUID pUuid, unsigned uOpenFlags,
446 unsigned uPercentStart, unsigned uPercentSpan,
447 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
448 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
449 void **ppBackendData)
450{
451 RT_NOREF1(pUuid);
452 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",
453 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
454
455 /* Check the VD container type. Yes, hard disk must be allowed, otherwise
456 * various tools using this backend for hard disk images will fail. */
457 if (enmType != VDTYPE_HDD && enmType != VDTYPE_OPTICAL_DISC && enmType != VDTYPE_FLOPPY)
458 return VERR_VD_INVALID_TYPE;
459
460 int rc = VINF_SUCCESS;
461 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
462
463 /* Check arguments. */
464 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
465 AssertReturn( VALID_PTR(pszFilename)
466 && *pszFilename
467 && VALID_PTR(pPCHSGeometry)
468 && VALID_PTR(pLCHSGeometry), VERR_INVALID_PARAMETER);
469
470 PRAWIMAGE pImage = (PRAWIMAGE)RTMemAllocZ(RT_UOFFSETOF(RAWIMAGE, RegionList.aRegions[1]));
471 if (RT_LIKELY(pImage))
472 {
473 pImage->pszFilename = pszFilename;
474 pImage->pStorage = NULL;
475 pImage->pVDIfsDisk = pVDIfsDisk;
476 pImage->pVDIfsImage = pVDIfsImage;
477
478 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
479 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
480 pIfProgress, uPercentStart, uPercentSpan);
481 if (RT_SUCCESS(rc))
482 {
483 /* So far the image is opened in read/write mode. Make sure the
484 * image is opened in read-only mode if the caller requested that. */
485 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
486 {
487 rawFreeImage(pImage, false);
488 rc = rawOpenImage(pImage, uOpenFlags);
489 }
490
491 if (RT_SUCCESS(rc))
492 *ppBackendData = pImage;
493 }
494
495 if (RT_FAILURE(rc))
496 RTMemFree(pImage);
497 }
498 else
499 rc = VERR_NO_MEMORY;
500
501 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
502 return rc;
503}
504
505/** @copydoc VDIMAGEBACKEND::pfnRename */
506static DECLCALLBACK(int) rawRename(void *pBackendData, const char *pszFilename)
507{
508 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
509 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
510
511 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
512
513 /* Close the image. */
514 int rc = rawFreeImage(pImage, false);
515 if (RT_SUCCESS(rc))
516 {
517 /* Rename the file. */
518 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
519 if (RT_SUCCESS(rc))
520 {
521 /* Update pImage with the new information. */
522 pImage->pszFilename = pszFilename;
523
524 /* Open the old image with new name. */
525 rc = rawOpenImage(pImage, pImage->uOpenFlags);
526 }
527 else
528 {
529 /* The move failed, try to reopen the original image. */
530 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
531 if (RT_FAILURE(rc2))
532 rc = rc2;
533 }
534 }
535
536 LogFlowFunc(("returns %Rrc\n", rc));
537 return rc;
538}
539
540/** @copydoc VDIMAGEBACKEND::pfnClose */
541static DECLCALLBACK(int) rawClose(void *pBackendData, bool fDelete)
542{
543 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
544 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
545 int rc = rawFreeImage(pImage, fDelete);
546 RTMemFree(pImage);
547
548 LogFlowFunc(("returns %Rrc\n", rc));
549 return rc;
550}
551
552/** @copydoc VDIMAGEBACKEND::pfnRead */
553static DECLCALLBACK(int) rawRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
554 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
555{
556 int rc = VINF_SUCCESS;
557 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
558
559 /* For sequential access do not allow to go back. */
560 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
561 && uOffset < pImage->offAccess)
562 {
563 *pcbActuallyRead = 0;
564 return VERR_INVALID_PARAMETER;
565 }
566
567 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
568 pIoCtx, cbToRead);
569 if (RT_SUCCESS(rc))
570 {
571 *pcbActuallyRead = cbToRead;
572 pImage->offAccess = uOffset + cbToRead;
573 }
574
575 return rc;
576}
577
578/** @copydoc VDIMAGEBACKEND::pfnWrite */
579static DECLCALLBACK(int) rawWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
580 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
581 size_t *pcbPostRead, unsigned fWrite)
582{
583 RT_NOREF1(fWrite);
584 int rc = VINF_SUCCESS;
585 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
586
587 /* For sequential access do not allow to go back. */
588 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
589 && uOffset < pImage->offAccess)
590 {
591 *pcbWriteProcess = 0;
592 *pcbPostRead = 0;
593 *pcbPreRead = 0;
594 return VERR_INVALID_PARAMETER;
595 }
596
597 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
598 pIoCtx, cbToWrite, NULL, NULL);
599 if (RT_SUCCESS(rc))
600 {
601 *pcbWriteProcess = cbToWrite;
602 *pcbPostRead = 0;
603 *pcbPreRead = 0;
604 pImage->offAccess = uOffset + cbToWrite;
605 }
606
607 return rc;
608}
609
610/** @copydoc VDIMAGEBACKEND::pfnFlush */
611static DECLCALLBACK(int) rawFlush(void *pBackendData, PVDIOCTX pIoCtx)
612{
613 int rc = VINF_SUCCESS;
614 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
615
616 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
617 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
618 NULL, NULL);
619
620 return rc;
621}
622
623/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
624static DECLCALLBACK(unsigned) rawGetVersion(void *pBackendData)
625{
626 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
627 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
628
629 AssertPtrReturn(pImage, 0);
630
631 return 1;
632}
633
634/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
635static DECLCALLBACK(uint64_t) rawGetFileSize(void *pBackendData)
636{
637 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
638 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
639
640 AssertPtrReturn(pImage, 0);
641
642 uint64_t cbFile = 0;
643 if (pImage->pStorage)
644 {
645 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
646 if (RT_FAILURE(rc))
647 cbFile = 0; /* Make sure it is 0 */
648 }
649
650 LogFlowFunc(("returns %lld\n", cbFile));
651 return cbFile;
652}
653
654/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
655static DECLCALLBACK(int) rawGetPCHSGeometry(void *pBackendData,
656 PVDGEOMETRY pPCHSGeometry)
657{
658 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
659 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
660 int rc = VINF_SUCCESS;
661
662 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
663
664 if (pImage->PCHSGeometry.cCylinders)
665 *pPCHSGeometry = pImage->PCHSGeometry;
666 else
667 rc = VERR_VD_GEOMETRY_NOT_SET;
668
669 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
670 return rc;
671}
672
673/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
674static DECLCALLBACK(int) rawSetPCHSGeometry(void *pBackendData,
675 PCVDGEOMETRY pPCHSGeometry)
676{
677 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n",
678 pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
679 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
680 int rc = VINF_SUCCESS;
681
682 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
683
684 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
685 rc = VERR_VD_IMAGE_READ_ONLY;
686 else
687 pImage->PCHSGeometry = *pPCHSGeometry;
688
689 LogFlowFunc(("returns %Rrc\n", rc));
690 return rc;
691}
692
693/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
694static DECLCALLBACK(int) rawGetLCHSGeometry(void *pBackendData,
695 PVDGEOMETRY pLCHSGeometry)
696{
697 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
698 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
699 int rc = VINF_SUCCESS;
700
701 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
702
703 if (pImage->LCHSGeometry.cCylinders)
704 *pLCHSGeometry = pImage->LCHSGeometry;
705 else
706 rc = VERR_VD_GEOMETRY_NOT_SET;
707
708 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
709 return rc;
710}
711
712/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
713static DECLCALLBACK(int) rawSetLCHSGeometry(void *pBackendData,
714 PCVDGEOMETRY pLCHSGeometry)
715{
716 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n",
717 pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
718 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
719 int rc = VINF_SUCCESS;
720
721 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
722
723 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
724 rc = VERR_VD_IMAGE_READ_ONLY;
725 else
726 pImage->LCHSGeometry = *pLCHSGeometry;
727
728 LogFlowFunc(("returns %Rrc\n", rc));
729 return rc;
730}
731
732/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
733static DECLCALLBACK(int) rawQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
734{
735 LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
736 PRAWIMAGE pThis = (PRAWIMAGE)pBackendData;
737
738 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
739
740 *ppRegionList = &pThis->RegionList;
741 LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
742 return VINF_SUCCESS;
743}
744
745/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
746static DECLCALLBACK(void) rawRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
747{
748 RT_NOREF1(pRegionList);
749 LogFlowFunc(("pBackendData=%#p pRegionList=%#p\n", pBackendData, pRegionList));
750 PRAWIMAGE pThis = (PRAWIMAGE)pBackendData;
751 AssertPtr(pThis); RT_NOREF(pThis);
752
753 /* Nothing to do here. */
754}
755
756/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
757static DECLCALLBACK(unsigned) rawGetImageFlags(void *pBackendData)
758{
759 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
760 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
761
762 AssertPtrReturn(pImage, 0);
763
764 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
765 return pImage->uImageFlags;
766}
767
768/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
769static DECLCALLBACK(unsigned) rawGetOpenFlags(void *pBackendData)
770{
771 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
772 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
773
774 AssertPtrReturn(pImage, 0);
775
776 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
777 return pImage->uOpenFlags;
778}
779
780/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
781static DECLCALLBACK(int) rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
782{
783 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
784 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
785 int rc = VINF_SUCCESS;
786
787 /* Image must be opened and the new flags must be valid. */
788 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
789 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
790 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
791 rc = VERR_INVALID_PARAMETER;
792 else
793 {
794 /* Implement this operation via reopening the image. */
795 rc = rawFreeImage(pImage, false);
796 if (RT_SUCCESS(rc))
797 rc = rawOpenImage(pImage, uOpenFlags);
798 }
799
800 LogFlowFunc(("returns %Rrc\n", rc));
801 return rc;
802}
803
804/** @copydoc VDIMAGEBACKEND::pfnGetComment */
805VD_BACKEND_CALLBACK_GET_COMMENT_DEF_NOT_SUPPORTED(rawGetComment);
806
807/** @copydoc VDIMAGEBACKEND::pfnSetComment */
808VD_BACKEND_CALLBACK_SET_COMMENT_DEF_NOT_SUPPORTED(rawSetComment, PRAWIMAGE);
809
810/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
811VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetUuid);
812
813/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
814VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetUuid, PRAWIMAGE);
815
816/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
817VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetModificationUuid);
818
819/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
820VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetModificationUuid, PRAWIMAGE);
821
822/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
823VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetParentUuid);
824
825/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
826VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetParentUuid, PRAWIMAGE);
827
828/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
829VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetParentModificationUuid);
830
831/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
832VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetParentModificationUuid, PRAWIMAGE);
833
834/** @copydoc VDIMAGEBACKEND::pfnDump */
835static DECLCALLBACK(void) rawDump(void *pBackendData)
836{
837 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
838
839 AssertPtrReturnVoid(pImage);
840 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
841 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
842 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
843 pImage->cbSize / 512);
844}
845
846
847
848const VDIMAGEBACKEND g_RawBackend =
849{
850 /* u32Version */
851 VD_IMGBACKEND_VERSION,
852 /* pszBackendName */
853 "RAW",
854 /* uBackendCaps */
855 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
856 /* paFileExtensions */
857 s_aRawFileExtensions,
858 /* paConfigInfo */
859 NULL,
860 /* pfnProbe */
861 rawProbe,
862 /* pfnOpen */
863 rawOpen,
864 /* pfnCreate */
865 rawCreate,
866 /* pfnRename */
867 rawRename,
868 /* pfnClose */
869 rawClose,
870 /* pfnRead */
871 rawRead,
872 /* pfnWrite */
873 rawWrite,
874 /* pfnFlush */
875 rawFlush,
876 /* pfnDiscard */
877 NULL,
878 /* pfnGetVersion */
879 rawGetVersion,
880 /* pfnGetFileSize */
881 rawGetFileSize,
882 /* pfnGetPCHSGeometry */
883 rawGetPCHSGeometry,
884 /* pfnSetPCHSGeometry */
885 rawSetPCHSGeometry,
886 /* pfnGetLCHSGeometry */
887 rawGetLCHSGeometry,
888 /* pfnSetLCHSGeometry */
889 rawSetLCHSGeometry,
890 /* pfnQueryRegions */
891 rawQueryRegions,
892 /* pfnRegionListRelease */
893 rawRegionListRelease,
894 /* pfnGetImageFlags */
895 rawGetImageFlags,
896 /* pfnGetOpenFlags */
897 rawGetOpenFlags,
898 /* pfnSetOpenFlags */
899 rawSetOpenFlags,
900 /* pfnGetComment */
901 rawGetComment,
902 /* pfnSetComment */
903 rawSetComment,
904 /* pfnGetUuid */
905 rawGetUuid,
906 /* pfnSetUuid */
907 rawSetUuid,
908 /* pfnGetModificationUuid */
909 rawGetModificationUuid,
910 /* pfnSetModificationUuid */
911 rawSetModificationUuid,
912 /* pfnGetParentUuid */
913 rawGetParentUuid,
914 /* pfnSetParentUuid */
915 rawSetParentUuid,
916 /* pfnGetParentModificationUuid */
917 rawGetParentModificationUuid,
918 /* pfnSetParentModificationUuid */
919 rawSetParentModificationUuid,
920 /* pfnDump */
921 rawDump,
922 /* pfnGetTimestamp */
923 NULL,
924 /* pfnGetParentTimestamp */
925 NULL,
926 /* pfnSetParentTimestamp */
927 NULL,
928 /* pfnGetParentFilename */
929 NULL,
930 /* pfnSetParentFilename */
931 NULL,
932 /* pfnComposeLocation */
933 genericFileComposeLocation,
934 /* pfnComposeName */
935 genericFileComposeName,
936 /* pfnCompact */
937 NULL,
938 /* pfnResize */
939 NULL,
940 /* pfnRepair */
941 NULL,
942 /* pfnTraverseMetadata */
943 NULL,
944 /* u32VersionEnd */
945 VD_IMGBACKEND_VERSION
946};
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