VirtualBox

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

Last change on this file since 77910 was 76553, checked in by vboxsync, 5 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 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * RawHDDCore - Raw Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 * bird: Not sure what this comment is mumbling about, the test below is 32KB not 1MB.
359 */
360 if (cbFile % 2048)
361 rc = VERR_VD_RAW_SIZE_MODULO_2048;
362 else if (cbFile <= 32768)
363 rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL;
364 else
365 {
366 *penmType = VDTYPE_OPTICAL_DISC;
367 rc = VINF_SUCCESS;
368 }
369 }
370 else if ( !RTStrICmp(pszSuffix, ".img")
371 || !RTStrICmp(pszSuffix, ".ima")
372 || !RTStrICmp(pszSuffix, ".dsk")
373 || !RTStrICmp(pszSuffix, ".flp")
374 || !RTStrICmp(pszSuffix, ".vfd")) /* Floppy images */
375 {
376 if (cbFile % 512)
377 rc = VERR_VD_RAW_SIZE_MODULO_512;
378 else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE)
379 rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG;
380 else
381 {
382 *penmType = VDTYPE_FLOPPY;
383 rc = VINF_SUCCESS;
384 }
385 }
386 else
387 rc = VERR_VD_RAW_INVALID_HEADER;
388 }
389 else
390 rc = VERR_VD_RAW_INVALID_HEADER;
391 }
392
393 if (pStorage)
394 vdIfIoIntFileClose(pIfIo, pStorage);
395
396 LogFlowFunc(("returns %Rrc\n", rc));
397 return rc;
398}
399
400/** @copydoc VDIMAGEBACKEND::pfnOpen */
401static DECLCALLBACK(int) rawOpen(const char *pszFilename, unsigned uOpenFlags,
402 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
403 VDTYPE enmType, void **ppBackendData)
404{
405 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
406 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
407 int rc;
408 PRAWIMAGE pImage;
409
410 /* Check open flags. All valid flags are supported. */
411 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
412 AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);
413
414 pImage = (PRAWIMAGE)RTMemAllocZ(RT_UOFFSETOF(RAWIMAGE, RegionList.aRegions[1]));
415 if (RT_LIKELY(pImage))
416 {
417 pImage->pszFilename = pszFilename;
418 pImage->pStorage = NULL;
419 pImage->pVDIfsDisk = pVDIfsDisk;
420 pImage->pVDIfsImage = pVDIfsImage;
421
422 if (enmType == VDTYPE_OPTICAL_DISC)
423 pImage->cbSector = 2048;
424 else
425 pImage->cbSector = 512;
426
427 rc = rawOpenImage(pImage, uOpenFlags);
428 if (RT_SUCCESS(rc))
429 *ppBackendData = pImage;
430 else
431 RTMemFree(pImage);
432 }
433 else
434 rc = VERR_NO_MEMORY;
435
436 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
437 return rc;
438}
439
440/** @copydoc VDIMAGEBACKEND::pfnCreate */
441static DECLCALLBACK(int) rawCreate(const char *pszFilename, uint64_t cbSize,
442 unsigned uImageFlags, const char *pszComment,
443 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
444 PCRTUUID pUuid, unsigned uOpenFlags,
445 unsigned uPercentStart, unsigned uPercentSpan,
446 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
447 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
448 void **ppBackendData)
449{
450 RT_NOREF1(pUuid);
451 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",
452 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
453
454 /* Check the VD container type. Yes, hard disk must be allowed, otherwise
455 * various tools using this backend for hard disk images will fail. */
456 if (enmType != VDTYPE_HDD && enmType != VDTYPE_OPTICAL_DISC && enmType != VDTYPE_FLOPPY)
457 return VERR_VD_INVALID_TYPE;
458
459 int rc = VINF_SUCCESS;
460 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
461
462 /* Check arguments. */
463 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
464 AssertReturn( VALID_PTR(pszFilename)
465 && *pszFilename
466 && VALID_PTR(pPCHSGeometry)
467 && VALID_PTR(pLCHSGeometry), VERR_INVALID_PARAMETER);
468
469 PRAWIMAGE pImage = (PRAWIMAGE)RTMemAllocZ(RT_UOFFSETOF(RAWIMAGE, RegionList.aRegions[1]));
470 if (RT_LIKELY(pImage))
471 {
472 pImage->pszFilename = pszFilename;
473 pImage->pStorage = NULL;
474 pImage->pVDIfsDisk = pVDIfsDisk;
475 pImage->pVDIfsImage = pVDIfsImage;
476
477 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
478 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
479 pIfProgress, uPercentStart, uPercentSpan);
480 if (RT_SUCCESS(rc))
481 {
482 /* So far the image is opened in read/write mode. Make sure the
483 * image is opened in read-only mode if the caller requested that. */
484 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
485 {
486 rawFreeImage(pImage, false);
487 rc = rawOpenImage(pImage, uOpenFlags);
488 }
489
490 if (RT_SUCCESS(rc))
491 *ppBackendData = pImage;
492 }
493
494 if (RT_FAILURE(rc))
495 RTMemFree(pImage);
496 }
497 else
498 rc = VERR_NO_MEMORY;
499
500 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
501 return rc;
502}
503
504/** @copydoc VDIMAGEBACKEND::pfnRename */
505static DECLCALLBACK(int) rawRename(void *pBackendData, const char *pszFilename)
506{
507 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
508 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
509
510 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
511
512 /* Close the image. */
513 int rc = rawFreeImage(pImage, false);
514 if (RT_SUCCESS(rc))
515 {
516 /* Rename the file. */
517 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
518 if (RT_SUCCESS(rc))
519 {
520 /* Update pImage with the new information. */
521 pImage->pszFilename = pszFilename;
522
523 /* Open the old image with new name. */
524 rc = rawOpenImage(pImage, pImage->uOpenFlags);
525 }
526 else
527 {
528 /* The move failed, try to reopen the original image. */
529 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
530 if (RT_FAILURE(rc2))
531 rc = rc2;
532 }
533 }
534
535 LogFlowFunc(("returns %Rrc\n", rc));
536 return rc;
537}
538
539/** @copydoc VDIMAGEBACKEND::pfnClose */
540static DECLCALLBACK(int) rawClose(void *pBackendData, bool fDelete)
541{
542 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
543 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
544 int rc = rawFreeImage(pImage, fDelete);
545 RTMemFree(pImage);
546
547 LogFlowFunc(("returns %Rrc\n", rc));
548 return rc;
549}
550
551/** @copydoc VDIMAGEBACKEND::pfnRead */
552static DECLCALLBACK(int) rawRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
553 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
554{
555 int rc = VINF_SUCCESS;
556 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
557
558 /* For sequential access do not allow to go back. */
559 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
560 && uOffset < pImage->offAccess)
561 {
562 *pcbActuallyRead = 0;
563 return VERR_INVALID_PARAMETER;
564 }
565
566 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
567 pIoCtx, cbToRead);
568 if (RT_SUCCESS(rc))
569 {
570 *pcbActuallyRead = cbToRead;
571 pImage->offAccess = uOffset + cbToRead;
572 }
573
574 return rc;
575}
576
577/** @copydoc VDIMAGEBACKEND::pfnWrite */
578static DECLCALLBACK(int) rawWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
579 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
580 size_t *pcbPostRead, unsigned fWrite)
581{
582 RT_NOREF1(fWrite);
583 int rc = VINF_SUCCESS;
584 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
585
586 /* For sequential access do not allow to go back. */
587 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
588 && uOffset < pImage->offAccess)
589 {
590 *pcbWriteProcess = 0;
591 *pcbPostRead = 0;
592 *pcbPreRead = 0;
593 return VERR_INVALID_PARAMETER;
594 }
595
596 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
597 pIoCtx, cbToWrite, NULL, NULL);
598 if (RT_SUCCESS(rc))
599 {
600 *pcbWriteProcess = cbToWrite;
601 *pcbPostRead = 0;
602 *pcbPreRead = 0;
603 pImage->offAccess = uOffset + cbToWrite;
604 }
605
606 return rc;
607}
608
609/** @copydoc VDIMAGEBACKEND::pfnFlush */
610static DECLCALLBACK(int) rawFlush(void *pBackendData, PVDIOCTX pIoCtx)
611{
612 int rc = VINF_SUCCESS;
613 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
614
615 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
616 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
617 NULL, NULL);
618
619 return rc;
620}
621
622/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
623static DECLCALLBACK(unsigned) rawGetVersion(void *pBackendData)
624{
625 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
626 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
627
628 AssertPtrReturn(pImage, 0);
629
630 return 1;
631}
632
633/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
634static DECLCALLBACK(uint64_t) rawGetFileSize(void *pBackendData)
635{
636 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
637 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
638
639 AssertPtrReturn(pImage, 0);
640
641 uint64_t cbFile = 0;
642 if (pImage->pStorage)
643 {
644 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
645 if (RT_FAILURE(rc))
646 cbFile = 0; /* Make sure it is 0 */
647 }
648
649 LogFlowFunc(("returns %lld\n", cbFile));
650 return cbFile;
651}
652
653/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
654static DECLCALLBACK(int) rawGetPCHSGeometry(void *pBackendData,
655 PVDGEOMETRY pPCHSGeometry)
656{
657 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
658 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
659 int rc = VINF_SUCCESS;
660
661 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
662
663 if (pImage->PCHSGeometry.cCylinders)
664 *pPCHSGeometry = pImage->PCHSGeometry;
665 else
666 rc = VERR_VD_GEOMETRY_NOT_SET;
667
668 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
669 return rc;
670}
671
672/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
673static DECLCALLBACK(int) rawSetPCHSGeometry(void *pBackendData,
674 PCVDGEOMETRY pPCHSGeometry)
675{
676 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n",
677 pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
678 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
679 int rc = VINF_SUCCESS;
680
681 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
682
683 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
684 rc = VERR_VD_IMAGE_READ_ONLY;
685 else
686 pImage->PCHSGeometry = *pPCHSGeometry;
687
688 LogFlowFunc(("returns %Rrc\n", rc));
689 return rc;
690}
691
692/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
693static DECLCALLBACK(int) rawGetLCHSGeometry(void *pBackendData,
694 PVDGEOMETRY pLCHSGeometry)
695{
696 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
697 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
698 int rc = VINF_SUCCESS;
699
700 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
701
702 if (pImage->LCHSGeometry.cCylinders)
703 *pLCHSGeometry = pImage->LCHSGeometry;
704 else
705 rc = VERR_VD_GEOMETRY_NOT_SET;
706
707 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
708 return rc;
709}
710
711/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
712static DECLCALLBACK(int) rawSetLCHSGeometry(void *pBackendData,
713 PCVDGEOMETRY pLCHSGeometry)
714{
715 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n",
716 pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
717 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
718 int rc = VINF_SUCCESS;
719
720 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
721
722 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
723 rc = VERR_VD_IMAGE_READ_ONLY;
724 else
725 pImage->LCHSGeometry = *pLCHSGeometry;
726
727 LogFlowFunc(("returns %Rrc\n", rc));
728 return rc;
729}
730
731/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
732static DECLCALLBACK(int) rawQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
733{
734 LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
735 PRAWIMAGE pThis = (PRAWIMAGE)pBackendData;
736
737 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
738
739 *ppRegionList = &pThis->RegionList;
740 LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
741 return VINF_SUCCESS;
742}
743
744/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
745static DECLCALLBACK(void) rawRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
746{
747 RT_NOREF1(pRegionList);
748 LogFlowFunc(("pBackendData=%#p pRegionList=%#p\n", pBackendData, pRegionList));
749 PRAWIMAGE pThis = (PRAWIMAGE)pBackendData;
750 AssertPtr(pThis); RT_NOREF(pThis);
751
752 /* Nothing to do here. */
753}
754
755/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
756static DECLCALLBACK(unsigned) rawGetImageFlags(void *pBackendData)
757{
758 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
759 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
760
761 AssertPtrReturn(pImage, 0);
762
763 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
764 return pImage->uImageFlags;
765}
766
767/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
768static DECLCALLBACK(unsigned) rawGetOpenFlags(void *pBackendData)
769{
770 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
771 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
772
773 AssertPtrReturn(pImage, 0);
774
775 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
776 return pImage->uOpenFlags;
777}
778
779/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
780static DECLCALLBACK(int) rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
781{
782 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
783 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
784 int rc = VINF_SUCCESS;
785
786 /* Image must be opened and the new flags must be valid. */
787 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
788 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
789 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
790 rc = VERR_INVALID_PARAMETER;
791 else
792 {
793 /* Implement this operation via reopening the image. */
794 rc = rawFreeImage(pImage, false);
795 if (RT_SUCCESS(rc))
796 rc = rawOpenImage(pImage, uOpenFlags);
797 }
798
799 LogFlowFunc(("returns %Rrc\n", rc));
800 return rc;
801}
802
803/** @copydoc VDIMAGEBACKEND::pfnGetComment */
804VD_BACKEND_CALLBACK_GET_COMMENT_DEF_NOT_SUPPORTED(rawGetComment);
805
806/** @copydoc VDIMAGEBACKEND::pfnSetComment */
807VD_BACKEND_CALLBACK_SET_COMMENT_DEF_NOT_SUPPORTED(rawSetComment, PRAWIMAGE);
808
809/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
810VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetUuid);
811
812/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
813VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetUuid, PRAWIMAGE);
814
815/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
816VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetModificationUuid);
817
818/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
819VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetModificationUuid, PRAWIMAGE);
820
821/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
822VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetParentUuid);
823
824/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
825VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetParentUuid, PRAWIMAGE);
826
827/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
828VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetParentModificationUuid);
829
830/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
831VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetParentModificationUuid, PRAWIMAGE);
832
833/** @copydoc VDIMAGEBACKEND::pfnDump */
834static DECLCALLBACK(void) rawDump(void *pBackendData)
835{
836 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
837
838 AssertPtrReturnVoid(pImage);
839 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
840 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
841 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
842 pImage->cbSize / 512);
843}
844
845
846
847const VDIMAGEBACKEND g_RawBackend =
848{
849 /* u32Version */
850 VD_IMGBACKEND_VERSION,
851 /* pszBackendName */
852 "RAW",
853 /* uBackendCaps */
854 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
855 /* paFileExtensions */
856 s_aRawFileExtensions,
857 /* paConfigInfo */
858 NULL,
859 /* pfnProbe */
860 rawProbe,
861 /* pfnOpen */
862 rawOpen,
863 /* pfnCreate */
864 rawCreate,
865 /* pfnRename */
866 rawRename,
867 /* pfnClose */
868 rawClose,
869 /* pfnRead */
870 rawRead,
871 /* pfnWrite */
872 rawWrite,
873 /* pfnFlush */
874 rawFlush,
875 /* pfnDiscard */
876 NULL,
877 /* pfnGetVersion */
878 rawGetVersion,
879 /* pfnGetFileSize */
880 rawGetFileSize,
881 /* pfnGetPCHSGeometry */
882 rawGetPCHSGeometry,
883 /* pfnSetPCHSGeometry */
884 rawSetPCHSGeometry,
885 /* pfnGetLCHSGeometry */
886 rawGetLCHSGeometry,
887 /* pfnSetLCHSGeometry */
888 rawSetLCHSGeometry,
889 /* pfnQueryRegions */
890 rawQueryRegions,
891 /* pfnRegionListRelease */
892 rawRegionListRelease,
893 /* pfnGetImageFlags */
894 rawGetImageFlags,
895 /* pfnGetOpenFlags */
896 rawGetOpenFlags,
897 /* pfnSetOpenFlags */
898 rawSetOpenFlags,
899 /* pfnGetComment */
900 rawGetComment,
901 /* pfnSetComment */
902 rawSetComment,
903 /* pfnGetUuid */
904 rawGetUuid,
905 /* pfnSetUuid */
906 rawSetUuid,
907 /* pfnGetModificationUuid */
908 rawGetModificationUuid,
909 /* pfnSetModificationUuid */
910 rawSetModificationUuid,
911 /* pfnGetParentUuid */
912 rawGetParentUuid,
913 /* pfnSetParentUuid */
914 rawSetParentUuid,
915 /* pfnGetParentModificationUuid */
916 rawGetParentModificationUuid,
917 /* pfnSetParentModificationUuid */
918 rawSetParentModificationUuid,
919 /* pfnDump */
920 rawDump,
921 /* pfnGetTimestamp */
922 NULL,
923 /* pfnGetParentTimestamp */
924 NULL,
925 /* pfnSetParentTimestamp */
926 NULL,
927 /* pfnGetParentFilename */
928 NULL,
929 /* pfnSetParentFilename */
930 NULL,
931 /* pfnComposeLocation */
932 genericFileComposeLocation,
933 /* pfnComposeName */
934 genericFileComposeName,
935 /* pfnCompact */
936 NULL,
937 /* pfnResize */
938 NULL,
939 /* pfnRepair */
940 NULL,
941 /* pfnTraverseMetadata */
942 NULL,
943 /* u32VersionEnd */
944 VD_IMGBACKEND_VERSION
945};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use