VirtualBox

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

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

Storage/RAW: Init sector size based on the type before actually opening the image

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: RAW.cpp 66489 2017-04-10 08:34:01Z vboxsync $ */
2/** @file
3 * RawHDDCore - Raw Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_VD_RAW
23#include <VBox/vd-plugin.h>
24#include <VBox/err.h>
25
26#include <VBox/log.h>
27#include <iprt/assert.h>
28#include <iprt/alloc.h>
29#include <iprt/path.h>
30
31#include "VDBackends.h"
32
33
34/*********************************************************************************************************************************
35* Constants And Macros, Structures and Typedefs *
36*********************************************************************************************************************************/
37
38/**
39 * Raw image data structure.
40 */
41typedef struct RAWIMAGE
42{
43 /** Image name. */
44 const char *pszFilename;
45 /** Storage handle. */
46 PVDIOSTORAGE pStorage;
47
48 /** Pointer to the per-disk VD interface list. */
49 PVDINTERFACE pVDIfsDisk;
50 /** Pointer to the per-image VD interface list. */
51 PVDINTERFACE pVDIfsImage;
52 /** Error interface. */
53 PVDINTERFACEERROR pIfError;
54 /** I/O interface. */
55 PVDINTERFACEIOINT pIfIo;
56
57 /** Open flags passed by VBoxHD layer. */
58 unsigned uOpenFlags;
59 /** Image flags defined during creation or determined during open. */
60 unsigned uImageFlags;
61 /** Total size of the image. */
62 uint64_t cbSize;
63 /** Position in the image (only truly used for sequential access). */
64 uint64_t offAccess;
65 /** Flag if this is a newly created image. */
66 bool fCreate;
67 /** Physical geometry of this image. */
68 VDGEOMETRY PCHSGeometry;
69 /** Logical geometry of this image. */
70 VDGEOMETRY LCHSGeometry;
71 /** Sector size of the image. */
72 uint32_t cbSector;
73 /** The static region list. */
74 VDREGIONLIST RegionList;
75} RAWIMAGE, *PRAWIMAGE;
76
77
78/** Size of write operations when filling an image with zeroes. */
79#define RAW_FILL_SIZE (128 * _1K)
80
81/** The maximum reasonable size of a floppy image (big format 2.88MB medium). */
82#define RAW_MAX_FLOPPY_IMG_SIZE (512 * 82 * 48 * 2)
83
84
85/*********************************************************************************************************************************
86* Static Variables *
87*********************************************************************************************************************************/
88
89/** NULL-terminated array of supported file extensions. */
90static const VDFILEEXTENSION s_aRawFileExtensions[] =
91{
92 {"iso", VDTYPE_OPTICAL_DISC},
93 {"cdr", VDTYPE_OPTICAL_DISC},
94 {"img", VDTYPE_FLOPPY},
95 {"ima", VDTYPE_FLOPPY},
96 {"dsk", VDTYPE_FLOPPY},
97 {"flp", VDTYPE_FLOPPY},
98 {"vfd", VDTYPE_FLOPPY},
99 {NULL, VDTYPE_INVALID}
100};
101
102
103/*********************************************************************************************************************************
104* Internal Functions *
105*********************************************************************************************************************************/
106
107/**
108 * Internal. Flush image data to disk.
109 */
110static int rawFlushImage(PRAWIMAGE pImage)
111{
112 int rc = VINF_SUCCESS;
113
114 if ( pImage->pStorage
115 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
116 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
117
118 return rc;
119}
120
121/**
122 * Internal. Free all allocated space for representing an image except pImage,
123 * and optionally delete the image from disk.
124 */
125static int rawFreeImage(PRAWIMAGE pImage, bool fDelete)
126{
127 int rc = VINF_SUCCESS;
128
129 /* Freeing a never allocated image (e.g. because the open failed) is
130 * not signalled as an error. After all nothing bad happens. */
131 if (pImage)
132 {
133 if (pImage->pStorage)
134 {
135 /* No point updating the file that is deleted anyway. */
136 if (!fDelete)
137 {
138 /* For newly created images in sequential mode fill it to
139 * the nominal size. */
140 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
141 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
142 && pImage->fCreate)
143 {
144 /* Fill rest of image with zeroes, a must for sequential
145 * images to reach the nominal size. */
146 uint64_t uOff;
147 void *pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
148 if (RT_LIKELY(pvBuf))
149 {
150 uOff = pImage->offAccess;
151 /* Write data to all image blocks. */
152 while (uOff < pImage->cbSize)
153 {
154 unsigned cbChunk = (unsigned)RT_MIN(pImage->cbSize - uOff,
155 RAW_FILL_SIZE);
156
157 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
158 uOff, pvBuf, cbChunk);
159 if (RT_FAILURE(rc))
160 break;
161
162 uOff += cbChunk;
163 }
164
165 RTMemTmpFree(pvBuf);
166 }
167 else
168 rc = VERR_NO_MEMORY;
169 }
170 rawFlushImage(pImage);
171 }
172
173 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
174 pImage->pStorage = NULL;
175 }
176
177 if (fDelete && pImage->pszFilename)
178 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
179 }
180
181 LogFlowFunc(("returns %Rrc\n", rc));
182 return rc;
183}
184
185/**
186 * Internal: Open an image, constructing all necessary data structures.
187 */
188static int rawOpenImage(PRAWIMAGE pImage, unsigned uOpenFlags)
189{
190 pImage->uOpenFlags = uOpenFlags;
191 pImage->fCreate = false;
192
193 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
194 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
195 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
196
197 /* Open the image. */
198 int rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
199 VDOpenFlagsToFileOpenFlags(uOpenFlags,
200 false /* fCreate */),
201 &pImage->pStorage);
202 if (RT_SUCCESS(rc))
203 {
204 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbSize);
205 if ( RT_SUCCESS(rc)
206 && !(pImage->cbSize % 512))
207 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
208 else if (RT_SUCCESS(rc))
209 rc = VERR_VD_RAW_SIZE_MODULO_512;
210 }
211 /* else: Do NOT signal an appropriate error here, as the VD layer has the
212 * choice of retrying the open if it failed. */
213
214 if (RT_SUCCESS(rc))
215 {
216 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
217 pImage->RegionList.fFlags = 0;
218 pImage->RegionList.cRegions = 1;
219
220 pRegion->offRegion = 0; /* Disk start. */
221 pRegion->cbBlock = pImage->cbSector;
222 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
223 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
224 pRegion->cbData = pImage->cbSector;
225 pRegion->cbMetadata = 0;
226 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
227 }
228 else
229 rawFreeImage(pImage, false);
230 return rc;
231}
232
233/**
234 * Internal: Create a raw image.
235 */
236static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize,
237 unsigned uImageFlags, const char *pszComment,
238 PCVDGEOMETRY pPCHSGeometry,
239 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
240 PVDINTERFACEPROGRESS pIfProgress,
241 unsigned uPercentStart, unsigned uPercentSpan)
242{
243 RT_NOREF1(pszComment);
244 int rc = VINF_SUCCESS;
245
246 pImage->fCreate = true;
247 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
248 pImage->uImageFlags = uImageFlags | VD_IMAGE_FLAGS_FIXED;
249 pImage->PCHSGeometry = *pPCHSGeometry;
250 pImage->LCHSGeometry = *pLCHSGeometry;
251 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
252 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
253 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
254
255 if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_DIFF))
256 {
257 /* Create image file. */
258 uint32_t fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
259 if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
260 fOpen &= ~RTFILE_O_READ;
261 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
262 if (RT_SUCCESS(rc))
263 {
264 if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
265 {
266 RTFOFF cbFree = 0;
267
268 /* Check the free space on the disk and leave early if there is not
269 * sufficient space available. */
270 rc = vdIfIoIntFileGetFreeSpace(pImage->pIfIo, pImage->pszFilename, &cbFree);
271 if (RT_FAILURE(rc) /* ignore errors */ || ((uint64_t)cbFree >= cbSize))
272 {
273 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pImage->pStorage, cbSize, 0 /* fFlags */,
274 pIfProgress, uPercentStart, uPercentSpan);
275 if (RT_SUCCESS(rc))
276 {
277 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 98 / 100);
278
279 pImage->cbSize = cbSize;
280 rc = rawFlushImage(pImage);
281 }
282 }
283 else
284 rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
285 }
286 else
287 {
288 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbSize);
289 if (RT_SUCCESS(rc))
290 pImage->cbSize = cbSize;
291 }
292 }
293 else
294 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
295 }
296 else
297 rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
298
299 if (RT_SUCCESS(rc))
300 {
301 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
302 pImage->RegionList.fFlags = 0;
303 pImage->RegionList.cRegions = 1;
304
305 pRegion->offRegion = 0; /* Disk start. */
306 pRegion->cbBlock = pImage->cbSector;
307 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
308 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
309 pRegion->cbData = pImage->cbSector;
310 pRegion->cbMetadata = 0;
311 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
312
313 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan);
314 }
315
316 if (RT_FAILURE(rc))
317 rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
318 return rc;
319}
320
321
322/** @copydoc VDIMAGEBACKEND::pfnProbe */
323static DECLCALLBACK(int) rawProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
324 PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
325{
326 RT_NOREF1(pVDIfsDisk);
327 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
328 PVDIOSTORAGE pStorage = NULL;
329 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
330
331 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
332 AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);
333
334 /*
335 * Open the file and read the footer.
336 */
337 int rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
338 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
339 false /* fCreate */),
340 &pStorage);
341 if (RT_SUCCESS(rc))
342 {
343 uint64_t cbFile;
344 const char *pszSuffix = RTPathSuffix(pszFilename);
345 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
346
347 /* Try to guess the image type based on the extension. */
348 if ( RT_SUCCESS(rc)
349 && pszSuffix)
350 {
351 if ( !RTStrICmp(pszSuffix, ".iso")
352 || !RTStrICmp(pszSuffix, ".cdr")) /* DVD images. */
353 {
354 /* Note that there are ISO images smaller than 1 MB; it is impossible to distinguish
355 * between raw floppy and CD images based on their size (and cannot be reliably done
356 * based on contents, either).
357 */
358 if (cbFile % 2048)
359 rc = VERR_VD_RAW_SIZE_MODULO_2048;
360 else if (cbFile <= 32768)
361 rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL;
362 else
363 {
364 *penmType = VDTYPE_OPTICAL_DISC;
365 rc = VINF_SUCCESS;
366 }
367 }
368 else if ( !RTStrICmp(pszSuffix, ".img")
369 || !RTStrICmp(pszSuffix, ".ima")
370 || !RTStrICmp(pszSuffix, ".dsk")
371 || !RTStrICmp(pszSuffix, ".flp")
372 || !RTStrICmp(pszSuffix, ".vfd")) /* Floppy images */
373 {
374 if (cbFile % 512)
375 rc = VERR_VD_RAW_SIZE_MODULO_512;
376 else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE)
377 rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG;
378 else
379 {
380 *penmType = VDTYPE_FLOPPY;
381 rc = VINF_SUCCESS;
382 }
383 }
384 else
385 rc = VERR_VD_RAW_INVALID_HEADER;
386 }
387 else
388 rc = VERR_VD_RAW_INVALID_HEADER;
389 }
390
391 if (pStorage)
392 vdIfIoIntFileClose(pIfIo, pStorage);
393
394 LogFlowFunc(("returns %Rrc\n", rc));
395 return rc;
396}
397
398/** @copydoc VDIMAGEBACKEND::pfnOpen */
399static DECLCALLBACK(int) rawOpen(const char *pszFilename, unsigned uOpenFlags,
400 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
401 VDTYPE enmType, void **ppBackendData)
402{
403 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
404 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
405 int rc;
406 PRAWIMAGE pImage;
407
408 NOREF(enmType); /**< @todo r=klaus make use of the type info. */
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 */
804static DECLCALLBACK(int) rawGetComment(void *pBackendData, char *pszComment,
805 size_t cbComment)
806{
807 RT_NOREF2(pszComment, cbComment);
808 LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
809 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
810
811 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
812
813 LogFlowFunc(("returns %Rrc comment='%s'\n", VERR_NOT_SUPPORTED, pszComment));
814 return VERR_NOT_SUPPORTED;
815}
816
817/** @copydoc VDIMAGEBACKEND::pfnSetComment */
818static DECLCALLBACK(int) rawSetComment(void *pBackendData, const char *pszComment)
819{
820 RT_NOREF1(pszComment);
821 LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
822 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
823
824 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
825
826 int rc;
827 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
828 rc = VERR_VD_IMAGE_READ_ONLY;
829 else
830 rc = VERR_NOT_SUPPORTED;
831
832 LogFlowFunc(("returns %Rrc\n", rc));
833 return rc;
834}
835
836/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
837static DECLCALLBACK(int) rawGetUuid(void *pBackendData, PRTUUID pUuid)
838{
839 RT_NOREF1(pUuid);
840 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
841 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
842
843 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
844
845 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
846 return VERR_NOT_SUPPORTED;
847}
848
849/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
850static DECLCALLBACK(int) rawSetUuid(void *pBackendData, PCRTUUID pUuid)
851{
852 RT_NOREF1(pUuid);
853 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
854 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
855
856 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
857
858 int rc;
859 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
860 rc = VERR_VD_IMAGE_READ_ONLY;
861 else
862 rc = VERR_NOT_SUPPORTED;
863
864 LogFlowFunc(("returns %Rrc\n", rc));
865 return rc;
866}
867
868/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
869static DECLCALLBACK(int) rawGetModificationUuid(void *pBackendData, PRTUUID pUuid)
870{
871 RT_NOREF1(pUuid);
872 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
873 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
874
875 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
876
877 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
878 return VERR_NOT_SUPPORTED;
879}
880
881/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
882static DECLCALLBACK(int) rawSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
883{
884 RT_NOREF1(pUuid);
885 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
886 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
887
888 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
889
890 int rc;
891 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
892 rc = VERR_VD_IMAGE_READ_ONLY;
893 else
894 rc = VERR_NOT_SUPPORTED;
895
896 LogFlowFunc(("returns %Rrc\n", rc));
897 return rc;
898}
899
900/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
901static DECLCALLBACK(int) rawGetParentUuid(void *pBackendData, PRTUUID pUuid)
902{
903 RT_NOREF1(pUuid);
904 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
905 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
906
907 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
908
909 LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
910 return VERR_NOT_SUPPORTED;
911}
912
913/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
914static DECLCALLBACK(int) rawSetParentUuid(void *pBackendData, PCRTUUID pUuid)
915{
916 RT_NOREF1(pUuid);
917 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
918 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
919
920 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
921
922 int rc;
923 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
924 rc = VERR_VD_IMAGE_READ_ONLY;
925 else
926 rc = VERR_NOT_SUPPORTED;
927
928 LogFlowFunc(("returns %Rrc\n", rc));
929 return rc;
930}
931
932/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
933static DECLCALLBACK(int) rawGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
934{
935 RT_NOREF1(pUuid);
936 LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
937 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
938
939 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
940
941 int rc;
942 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
943 rc = VERR_VD_IMAGE_READ_ONLY;
944 else
945 rc = VERR_NOT_SUPPORTED;
946
947 LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
948 return rc;
949}
950
951/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
952static DECLCALLBACK(int) rawSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
953{
954 RT_NOREF1(pUuid);
955 LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
956 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
957
958 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
959
960 int rc;
961 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
962 rc = VERR_VD_IMAGE_READ_ONLY;
963 else
964 rc = VERR_NOT_SUPPORTED;
965
966 LogFlowFunc(("returns %Rrc\n", rc));
967 return rc;
968}
969
970/** @copydoc VDIMAGEBACKEND::pfnDump */
971static DECLCALLBACK(void) rawDump(void *pBackendData)
972{
973 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
974
975 AssertPtrReturnVoid(pImage);
976 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
977 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
978 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
979 pImage->cbSize / 512);
980}
981
982
983
984const VDIMAGEBACKEND g_RawBackend =
985{
986 /* u32Version */
987 VD_IMGBACKEND_VERSION,
988 /* pszBackendName */
989 "RAW",
990 /* uBackendCaps */
991 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
992 /* paFileExtensions */
993 s_aRawFileExtensions,
994 /* paConfigInfo */
995 NULL,
996 /* pfnProbe */
997 rawProbe,
998 /* pfnOpen */
999 rawOpen,
1000 /* pfnCreate */
1001 rawCreate,
1002 /* pfnRename */
1003 rawRename,
1004 /* pfnClose */
1005 rawClose,
1006 /* pfnRead */
1007 rawRead,
1008 /* pfnWrite */
1009 rawWrite,
1010 /* pfnFlush */
1011 rawFlush,
1012 /* pfnDiscard */
1013 NULL,
1014 /* pfnGetVersion */
1015 rawGetVersion,
1016 /* pfnGetFileSize */
1017 rawGetFileSize,
1018 /* pfnGetPCHSGeometry */
1019 rawGetPCHSGeometry,
1020 /* pfnSetPCHSGeometry */
1021 rawSetPCHSGeometry,
1022 /* pfnGetLCHSGeometry */
1023 rawGetLCHSGeometry,
1024 /* pfnSetLCHSGeometry */
1025 rawSetLCHSGeometry,
1026 /* pfnQueryRegions */
1027 rawQueryRegions,
1028 /* pfnRegionListRelease */
1029 rawRegionListRelease,
1030 /* pfnGetImageFlags */
1031 rawGetImageFlags,
1032 /* pfnGetOpenFlags */
1033 rawGetOpenFlags,
1034 /* pfnSetOpenFlags */
1035 rawSetOpenFlags,
1036 /* pfnGetComment */
1037 rawGetComment,
1038 /* pfnSetComment */
1039 rawSetComment,
1040 /* pfnGetUuid */
1041 rawGetUuid,
1042 /* pfnSetUuid */
1043 rawSetUuid,
1044 /* pfnGetModificationUuid */
1045 rawGetModificationUuid,
1046 /* pfnSetModificationUuid */
1047 rawSetModificationUuid,
1048 /* pfnGetParentUuid */
1049 rawGetParentUuid,
1050 /* pfnSetParentUuid */
1051 rawSetParentUuid,
1052 /* pfnGetParentModificationUuid */
1053 rawGetParentModificationUuid,
1054 /* pfnSetParentModificationUuid */
1055 rawSetParentModificationUuid,
1056 /* pfnDump */
1057 rawDump,
1058 /* pfnGetTimestamp */
1059 NULL,
1060 /* pfnGetParentTimestamp */
1061 NULL,
1062 /* pfnSetParentTimestamp */
1063 NULL,
1064 /* pfnGetParentFilename */
1065 NULL,
1066 /* pfnSetParentFilename */
1067 NULL,
1068 /* pfnComposeLocation */
1069 genericFileComposeLocation,
1070 /* pfnComposeName */
1071 genericFileComposeName,
1072 /* pfnCompact */
1073 NULL,
1074 /* pfnResize */
1075 NULL,
1076 /* pfnRepair */
1077 NULL,
1078 /* pfnTraverseMetadata */
1079 NULL,
1080 /* u32VersionEnd */
1081 VD_IMGBACKEND_VERSION
1082};
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