VirtualBox

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

Last change on this file since 90520 was 86500, checked in by vboxsync, 4 years ago

Storage/RAW: Allow sector sized floppy images like bs-shutdown.img.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.8 KB
Line 
1/* $Id: RAW.cpp 86500 2020-10-08 17:07:38Z vboxsync $ */
2/** @file
3 * RawHDDCore - Raw Disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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#include <iprt/formats/iso9660.h>
31#include <iprt/formats/udf.h>
32
33#include "VDBackends.h"
34#include "VDBackendsInline.h"
35
36
37/*********************************************************************************************************************************
38* Constants And Macros, Structures and Typedefs *
39*********************************************************************************************************************************/
40
41/**
42 * Raw image data structure.
43 */
44typedef struct RAWIMAGE
45{
46 /** Image name. */
47 const char *pszFilename;
48 /** Storage handle. */
49 PVDIOSTORAGE pStorage;
50
51 /** Pointer to the per-disk VD interface list. */
52 PVDINTERFACE pVDIfsDisk;
53 /** Pointer to the per-image VD interface list. */
54 PVDINTERFACE pVDIfsImage;
55 /** Error interface. */
56 PVDINTERFACEERROR pIfError;
57 /** I/O interface. */
58 PVDINTERFACEIOINT pIfIo;
59
60 /** Open flags passed by VBoxHD layer. */
61 unsigned uOpenFlags;
62 /** Image flags defined during creation or determined during open. */
63 unsigned uImageFlags;
64 /** Total size of the image. */
65 uint64_t cbSize;
66 /** Position in the image (only truly used for sequential access). */
67 uint64_t offAccess;
68 /** Flag if this is a newly created image. */
69 bool fCreate;
70 /** Physical geometry of this image. */
71 VDGEOMETRY PCHSGeometry;
72 /** Logical geometry of this image. */
73 VDGEOMETRY LCHSGeometry;
74 /** Sector size of the image. */
75 uint32_t cbSector;
76 /** The static region list. */
77 VDREGIONLIST RegionList;
78} RAWIMAGE, *PRAWIMAGE;
79
80
81/** Size of write operations when filling an image with zeroes. */
82#define RAW_FILL_SIZE (128 * _1K)
83
84/** The maximum reasonable size of a floppy image (big format 2.88MB medium). */
85#define RAW_MAX_FLOPPY_IMG_SIZE (512 * 82 * 48 * 2)
86
87
88/*********************************************************************************************************************************
89* Static Variables *
90*********************************************************************************************************************************/
91
92/** NULL-terminated array of supported file extensions. */
93static const VDFILEEXTENSION s_aRawFileExtensions[] =
94{
95 {"iso", VDTYPE_OPTICAL_DISC},
96 {"cdr", VDTYPE_OPTICAL_DISC},
97 {"img", VDTYPE_FLOPPY},
98 {"ima", VDTYPE_FLOPPY},
99 {"dsk", VDTYPE_FLOPPY},
100 {"flp", VDTYPE_FLOPPY},
101 {"vfd", VDTYPE_FLOPPY},
102 {NULL, VDTYPE_INVALID}
103};
104
105
106/*********************************************************************************************************************************
107* Internal Functions *
108*********************************************************************************************************************************/
109
110/**
111 * Internal. Flush image data to disk.
112 */
113static int rawFlushImage(PRAWIMAGE pImage)
114{
115 int rc = VINF_SUCCESS;
116
117 if ( pImage->pStorage
118 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
119 rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
120
121 return rc;
122}
123
124/**
125 * Internal. Free all allocated space for representing an image except pImage,
126 * and optionally delete the image from disk.
127 */
128static int rawFreeImage(PRAWIMAGE pImage, bool fDelete)
129{
130 int rc = VINF_SUCCESS;
131
132 /* Freeing a never allocated image (e.g. because the open failed) is
133 * not signalled as an error. After all nothing bad happens. */
134 if (pImage)
135 {
136 if (pImage->pStorage)
137 {
138 /* No point updating the file that is deleted anyway. */
139 if (!fDelete)
140 {
141 /* For newly created images in sequential mode fill it to
142 * the nominal size. */
143 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
144 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
145 && pImage->fCreate)
146 {
147 /* Fill rest of image with zeroes, a must for sequential
148 * images to reach the nominal size. */
149 uint64_t uOff;
150 void *pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
151 if (RT_LIKELY(pvBuf))
152 {
153 uOff = pImage->offAccess;
154 /* Write data to all image blocks. */
155 while (uOff < pImage->cbSize)
156 {
157 unsigned cbChunk = (unsigned)RT_MIN(pImage->cbSize - uOff,
158 RAW_FILL_SIZE);
159
160 rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
161 uOff, pvBuf, cbChunk);
162 if (RT_FAILURE(rc))
163 break;
164
165 uOff += cbChunk;
166 }
167
168 RTMemTmpFree(pvBuf);
169 }
170 else
171 rc = VERR_NO_MEMORY;
172 }
173 rawFlushImage(pImage);
174 }
175
176 rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
177 pImage->pStorage = NULL;
178 }
179
180 if (fDelete && pImage->pszFilename)
181 vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
182 }
183
184 LogFlowFunc(("returns %Rrc\n", rc));
185 return rc;
186}
187
188/**
189 * Internal: Open an image, constructing all necessary data structures.
190 */
191static int rawOpenImage(PRAWIMAGE pImage, unsigned uOpenFlags)
192{
193 pImage->uOpenFlags = uOpenFlags;
194 pImage->fCreate = false;
195
196 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
197 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
198 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
199
200 /* Open the image. */
201 int rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
202 VDOpenFlagsToFileOpenFlags(uOpenFlags,
203 false /* fCreate */),
204 &pImage->pStorage);
205 if (RT_SUCCESS(rc))
206 {
207 rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbSize);
208 if ( RT_SUCCESS(rc)
209 && !(pImage->cbSize % 512))
210 pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
211 else if (RT_SUCCESS(rc))
212 rc = VERR_VD_RAW_SIZE_MODULO_512;
213 }
214 /* else: Do NOT signal an appropriate error here, as the VD layer has the
215 * choice of retrying the open if it failed. */
216
217 if (RT_SUCCESS(rc))
218 {
219 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
220 pImage->RegionList.fFlags = 0;
221 pImage->RegionList.cRegions = 1;
222
223 pRegion->offRegion = 0; /* Disk start. */
224 pRegion->cbBlock = pImage->cbSector;
225 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
226 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
227 pRegion->cbData = pImage->cbSector;
228 pRegion->cbMetadata = 0;
229 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
230 }
231 else
232 rawFreeImage(pImage, false);
233 return rc;
234}
235
236/**
237 * Internal: Create a raw image.
238 */
239static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize,
240 unsigned uImageFlags, const char *pszComment,
241 PCVDGEOMETRY pPCHSGeometry,
242 PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
243 PVDINTERFACEPROGRESS pIfProgress,
244 unsigned uPercentStart, unsigned uPercentSpan)
245{
246 RT_NOREF1(pszComment);
247 int rc = VINF_SUCCESS;
248
249 pImage->fCreate = true;
250 pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
251 pImage->uImageFlags = uImageFlags | VD_IMAGE_FLAGS_FIXED;
252 pImage->PCHSGeometry = *pPCHSGeometry;
253 pImage->LCHSGeometry = *pLCHSGeometry;
254 pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
255 pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
256 AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
257
258 if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_DIFF))
259 {
260 /* Create image file. */
261 uint32_t fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
262 if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
263 fOpen &= ~RTFILE_O_READ;
264 rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
265 if (RT_SUCCESS(rc))
266 {
267 if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
268 {
269 RTFOFF cbFree = 0;
270
271 /* Check the free space on the disk and leave early if there is not
272 * sufficient space available. */
273 rc = vdIfIoIntFileGetFreeSpace(pImage->pIfIo, pImage->pszFilename, &cbFree);
274 if (RT_FAILURE(rc) /* ignore errors */ || ((uint64_t)cbFree >= cbSize))
275 {
276 rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pImage->pStorage, cbSize, 0 /* fFlags */,
277 pIfProgress, uPercentStart, uPercentSpan);
278 if (RT_SUCCESS(rc))
279 {
280 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 98 / 100);
281
282 pImage->cbSize = cbSize;
283 rc = rawFlushImage(pImage);
284 }
285 }
286 else
287 rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
288 }
289 else
290 {
291 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbSize);
292 if (RT_SUCCESS(rc))
293 pImage->cbSize = cbSize;
294 }
295 }
296 else
297 rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
298 }
299 else
300 rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
301
302 if (RT_SUCCESS(rc))
303 {
304 PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
305 pImage->RegionList.fFlags = 0;
306 pImage->RegionList.cRegions = 1;
307
308 pRegion->offRegion = 0; /* Disk start. */
309 pRegion->cbBlock = pImage->cbSector;
310 pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
311 pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
312 pRegion->cbData = pImage->cbSector;
313 pRegion->cbMetadata = 0;
314 pRegion->cRegionBlocksOrBytes = pImage->cbSize;
315
316 vdIfProgress(pIfProgress, uPercentStart + uPercentSpan);
317 }
318
319 if (RT_FAILURE(rc))
320 rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
321 return rc;
322}
323
324/**
325 * Worker for rawProbe that checks if the file looks like it contains an ISO
326 * 9660 or UDF descriptor sequence at the expected offset.
327 *
328 * Caller already checked if the size is suitable for ISOs.
329 *
330 * @returns IPRT status code. Success if detected ISO 9660 or UDF, failure if
331 * not.
332 *
333 * @note Code is a modified version of rtFsIsoVolTryInit() IPRT (isovfs.cpp).
334 */
335static int rawProbeIsIso9660OrUdf(PVDINTERFACEIOINT pIfIo, PVDIOSTORAGE pStorage)
336{
337 PRTERRINFO pErrInfo = NULL;
338 const uint32_t cbSector = _2K;
339
340 union
341 {
342 uint8_t ab[_2K];
343 ISO9660VOLDESCHDR VolDescHdr;
344 } Buf;
345 Assert(cbSector <= sizeof(Buf));
346 RT_ZERO(Buf);
347
348 uint8_t uUdfLevel = 0;
349 uint64_t offUdfBootVolDesc = UINT64_MAX;
350
351 uint32_t cPrimaryVolDescs = 0;
352 uint32_t cSupplementaryVolDescs = 0;
353 uint32_t cBootRecordVolDescs = 0;
354 uint32_t offVolDesc = 16 * cbSector;
355 enum
356 {
357 kStateStart = 0,
358 kStateNoSeq,
359 kStateCdSeq,
360 kStateUdfSeq
361 } enmState = kStateStart;
362 for (uint32_t iVolDesc = 0; ; iVolDesc++, offVolDesc += cbSector)
363 {
364 if (iVolDesc > 32)
365 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "More than 32 volume descriptors, doesn't seem right...");
366
367 /* Read the next one and check the signature. */
368 int rc = vdIfIoIntFileReadSync(pIfIo, pStorage, offVolDesc, &Buf, cbSector);
369 if (RT_FAILURE(rc))
370 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "Unable to read volume descriptor #%u", iVolDesc);
371
372#define MATCH_STD_ID(a_achStdId1, a_szStdId2) \
373 ( (a_achStdId1)[0] == (a_szStdId2)[0] \
374 && (a_achStdId1)[1] == (a_szStdId2)[1] \
375 && (a_achStdId1)[2] == (a_szStdId2)[2] \
376 && (a_achStdId1)[3] == (a_szStdId2)[3] \
377 && (a_achStdId1)[4] == (a_szStdId2)[4] )
378#define MATCH_HDR(a_pStd, a_bType2, a_szStdId2, a_bVer2) \
379 ( MATCH_STD_ID((a_pStd)->achStdId, a_szStdId2) \
380 && (a_pStd)->bDescType == (a_bType2) \
381 && (a_pStd)->bDescVersion == (a_bVer2) )
382
383 /*
384 * ISO 9660 ("CD001").
385 */
386 if ( ( enmState == kStateStart
387 || enmState == kStateCdSeq
388 || enmState == kStateNoSeq)
389 && MATCH_STD_ID(Buf.VolDescHdr.achStdId, ISO9660VOLDESC_STD_ID) )
390 {
391 enmState = kStateCdSeq;
392
393 /* Do type specific handling. */
394 Log(("RAW/ISO9660: volume desc #%u: type=%#x\n", iVolDesc, Buf.VolDescHdr.bDescType));
395 if (Buf.VolDescHdr.bDescType == ISO9660VOLDESC_TYPE_PRIMARY)
396 {
397 cPrimaryVolDescs++;
398 if (Buf.VolDescHdr.bDescVersion != ISO9660PRIMARYVOLDESC_VERSION)
399 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
400 "Unsupported primary volume descriptor version: %#x", Buf.VolDescHdr.bDescVersion);
401 if (cPrimaryVolDescs == 1)
402 { /*rc = rtFsIsoVolHandlePrimaryVolDesc(pThis, &Buf.PrimaryVolDesc, offVolDesc, &RootDir, &offRootDirRec, pErrInfo);*/ }
403 else if (cPrimaryVolDescs == 2)
404 Log(("RAW/ISO9660: ignoring 2nd primary descriptor\n")); /* so we can read the w2k3 ifs kit */
405 else
406 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "More than one primary volume descriptor");
407 }
408 else if (Buf.VolDescHdr.bDescType == ISO9660VOLDESC_TYPE_SUPPLEMENTARY)
409 {
410 cSupplementaryVolDescs++;
411 if (Buf.VolDescHdr.bDescVersion != ISO9660SUPVOLDESC_VERSION)
412 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
413 "Unsupported supplemental volume descriptor version: %#x", Buf.VolDescHdr.bDescVersion);
414 /*rc = rtFsIsoVolHandleSupplementaryVolDesc(pThis, &Buf.SupVolDesc, offVolDesc, &bJolietUcs2Level, &JolietRootDir,
415 &offJolietRootDirRec, pErrInfo);*/
416 }
417 else if (Buf.VolDescHdr.bDescType == ISO9660VOLDESC_TYPE_BOOT_RECORD)
418 {
419 cBootRecordVolDescs++;
420 }
421 else if (Buf.VolDescHdr.bDescType == ISO9660VOLDESC_TYPE_TERMINATOR)
422 {
423 if (!cPrimaryVolDescs)
424 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_BOGUS_FORMAT, "No primary volume descriptor");
425 enmState = kStateNoSeq;
426 }
427 else
428 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
429 "Unknown volume descriptor: %#x", Buf.VolDescHdr.bDescType);
430 }
431 /*
432 * UDF volume recognition sequence (VRS).
433 */
434 else if ( ( enmState == kStateNoSeq
435 || enmState == kStateStart)
436 && MATCH_HDR(&Buf.VolDescHdr, UDF_EXT_VOL_DESC_TYPE, UDF_EXT_VOL_DESC_STD_ID_BEGIN, UDF_EXT_VOL_DESC_VERSION) )
437 {
438 if (uUdfLevel == 0)
439 enmState = kStateUdfSeq;
440 else
441 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Only one BEA01 sequence is supported");
442 }
443 else if ( enmState == kStateUdfSeq
444 && MATCH_HDR(&Buf.VolDescHdr, UDF_EXT_VOL_DESC_TYPE, UDF_EXT_VOL_DESC_STD_ID_NSR_02, UDF_EXT_VOL_DESC_VERSION) )
445 uUdfLevel = 2;
446 else if ( enmState == kStateUdfSeq
447 && MATCH_HDR(&Buf.VolDescHdr, UDF_EXT_VOL_DESC_TYPE, UDF_EXT_VOL_DESC_STD_ID_NSR_03, UDF_EXT_VOL_DESC_VERSION) )
448 uUdfLevel = 3;
449 else if ( enmState == kStateUdfSeq
450 && MATCH_HDR(&Buf.VolDescHdr, UDF_EXT_VOL_DESC_TYPE, UDF_EXT_VOL_DESC_STD_ID_BOOT, UDF_EXT_VOL_DESC_VERSION) )
451 {
452 if (offUdfBootVolDesc == UINT64_MAX)
453 offUdfBootVolDesc = iVolDesc * cbSector;
454 else
455 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Only one BOOT2 descriptor is supported");
456 }
457 else if ( enmState == kStateUdfSeq
458 && MATCH_HDR(&Buf.VolDescHdr, UDF_EXT_VOL_DESC_TYPE, UDF_EXT_VOL_DESC_STD_ID_TERM, UDF_EXT_VOL_DESC_VERSION) )
459 {
460 if (uUdfLevel != 0)
461 enmState = kStateNoSeq;
462 else
463 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT, "Found BEA01 & TEA01, but no NSR02 or NSR03 descriptors");
464 }
465 /*
466 * Unknown, probably the end.
467 */
468 else if (enmState == kStateNoSeq)
469 break;
470 else if (enmState == kStateStart)
471 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNKNOWN_FORMAT,
472 "Not ISO? Unable to recognize volume descriptor signature: %.5Rhxs", Buf.VolDescHdr.achStdId);
473 else if (enmState == kStateCdSeq)
474 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
475 "Missing ISO 9660 terminator volume descriptor? (Found %.5Rhxs)", Buf.VolDescHdr.achStdId);
476 else if (enmState == kStateUdfSeq)
477 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_BOGUS_FORMAT,
478 "Missing UDF terminator volume descriptor? (Found %.5Rhxs)", Buf.VolDescHdr.achStdId);
479 else
480 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNKNOWN_FORMAT,
481 "Unknown volume descriptor signature found at sector %u: %.5Rhxs",
482 16 + iVolDesc, Buf.VolDescHdr.achStdId);
483 }
484
485 return VINF_SUCCESS;
486}
487
488/**
489 * Checks the given extension array for the given suffix and type.
490 *
491 * @returns true if found in the list, false if not.
492 * @param paExtensions The extension array to check against.
493 * @param pszSuffix The suffix to look for. Can be NULL.
494 * @param enmType The image type to look for.
495 */
496static bool rawProbeContainsExtension(const VDFILEEXTENSION *paExtensions, const char *pszSuffix, VDTYPE enmType)
497{
498 if (pszSuffix)
499 {
500 if (*pszSuffix == '.')
501 pszSuffix++;
502 if (*pszSuffix != '\0')
503 {
504 for (size_t i = 0;; i++)
505 {
506 if (!paExtensions[i].pszExtension)
507 break;
508 if ( paExtensions[i].enmType == enmType
509 && RTStrICmpAscii(paExtensions[i].pszExtension, pszSuffix) == 0)
510 return true;
511 }
512 }
513 }
514 return false;
515}
516
517
518/** @copydoc VDIMAGEBACKEND::pfnProbe */
519static DECLCALLBACK(int) rawProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
520 PVDINTERFACE pVDIfsImage, VDTYPE enmDesiredType, VDTYPE *penmType)
521{
522 RT_NOREF(pVDIfsDisk, enmDesiredType);
523 LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
524 PVDIOSTORAGE pStorage = NULL;
525 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
526
527 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
528 AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);
529
530 /*
531 * Open the file and read the footer.
532 */
533 int rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
534 VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
535 false /* fCreate */),
536 &pStorage);
537 if (RT_SUCCESS(rc))
538 {
539 uint64_t cbFile;
540 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
541 if (RT_SUCCESS(rc))
542 {
543 /*
544 * Detecting raw ISO and floppy images and keeping them apart isn't all
545 * that simple.
546 *
547 * - Both must be a multiple of their sector sizes, though
548 * that means that any ISO can also be a floppy, since 2048 is 512 * 4.
549 * - The ISO images must be 32KB and floppies are generally not larger
550 * than 2.88MB, but that leaves quite a bit of size overlap,
551 *
552 * So, the size cannot conclusively say whether something is one or the other.
553 *
554 * - The content of a normal ISO image is detectable, but not all ISO
555 * images need to follow that spec to work in a DVD ROM drive.
556 * - It is common for ISO images to start like a floppy with a boot sector
557 * at the very start of the image.
558 * - Floppies doesn't need to contain a DOS-style boot sector, it depends
559 * on the system it is formatted and/or intended for.
560 *
561 * So, the content cannot conclusively determine the type either.
562 *
563 * However, there are a number of cases, especially for ISOs, where we can
564 * say we a deal of confidence that something is an ISO image.
565 */
566 const char * const pszSuffix = RTPathSuffix(pszFilename);
567
568 /*
569 * Start by checking for sure signs of an ISO 9660 / UDF image.
570 */
571 rc = VERR_VD_RAW_INVALID_HEADER;
572 if ( (enmDesiredType == VDTYPE_INVALID || enmDesiredType == VDTYPE_OPTICAL_DISC)
573 && (cbFile % 2048) == 0
574 && cbFile > 32768)
575 {
576 int rc2 = rawProbeIsIso9660OrUdf(pIfIo, pStorage);
577 if (RT_SUCCESS(rc2))
578 {
579 /* *puScore = VDPROBE_SCORE_HIGH; */
580 *penmType = VDTYPE_OPTICAL_DISC;
581 rc = VINF_SUCCESS;
582 }
583 /* If that didn't work out, check by extension (the old way): */
584 else if (rawProbeContainsExtension(s_aRawFileExtensions, pszSuffix, VDTYPE_OPTICAL_DISC))
585 {
586 /* *puScore = VDPROBE_SCORE_LOW; */
587 *penmType = VDTYPE_OPTICAL_DISC;
588 rc = VINF_SUCCESS;
589 }
590 }
591
592 /*
593 * We could do something similar for floppies, i.e. check for a
594 * DOS'ish boot sector and thereby get a good match on most of the
595 * relevant floppy images out there.
596 */
597 if ( RT_FAILURE(rc)
598 && (enmDesiredType == VDTYPE_INVALID || enmDesiredType == VDTYPE_FLOPPY)
599 && (cbFile % 512) == 0
600 && cbFile >= 512
601 && cbFile <= RAW_MAX_FLOPPY_IMG_SIZE)
602 {
603 /** @todo check if the content is DOSish. */
604 if (false)
605 {
606 /* *puScore = VDPROBE_SCORE_HIGH; */
607 *penmType = VDTYPE_FLOPPY;
608 rc = VINF_SUCCESS;
609 }
610 else if (rawProbeContainsExtension(s_aRawFileExtensions, pszSuffix, VDTYPE_FLOPPY))
611 {
612 /* *puScore = VDPROBE_SCORE_LOW; */
613 *penmType = VDTYPE_FLOPPY;
614 rc = VINF_SUCCESS;
615 }
616 }
617
618 /*
619 * No luck? Go exclusively by extension like we've done since
620 * for ever and complain about the size if it doesn't fit expectations.
621 * We can get here if the desired type doesn't match the extension and such.
622 */
623 if (RT_FAILURE(rc))
624 {
625 if (rawProbeContainsExtension(s_aRawFileExtensions, pszSuffix, VDTYPE_OPTICAL_DISC))
626 {
627 if (cbFile % 2048)
628 rc = VERR_VD_RAW_SIZE_MODULO_2048;
629 else if (cbFile <= 32768)
630 rc = VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL;
631 else
632 {
633 Assert(enmDesiredType != VDTYPE_OPTICAL_DISC);
634 *penmType = VDTYPE_OPTICAL_DISC;
635 rc = VINF_SUCCESS;
636 }
637 }
638 else if (rawProbeContainsExtension(s_aRawFileExtensions, pszSuffix, VDTYPE_FLOPPY))
639 {
640 if (cbFile % 512)
641 rc = VERR_VD_RAW_SIZE_MODULO_512;
642 else if (cbFile > RAW_MAX_FLOPPY_IMG_SIZE)
643 rc = VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG;
644 else
645 {
646 Assert(cbFile == 0 || enmDesiredType != VDTYPE_FLOPPY);
647 *penmType = VDTYPE_FLOPPY;
648 rc = VINF_SUCCESS;
649 }
650 }
651 else
652 rc = VERR_VD_RAW_INVALID_HEADER;
653 }
654 }
655 else
656 rc = VERR_VD_RAW_INVALID_HEADER;
657 }
658
659 if (pStorage)
660 vdIfIoIntFileClose(pIfIo, pStorage);
661
662 LogFlowFunc(("returns %Rrc\n", rc));
663 return rc;
664}
665
666/** @copydoc VDIMAGEBACKEND::pfnOpen */
667static DECLCALLBACK(int) rawOpen(const char *pszFilename, unsigned uOpenFlags,
668 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
669 VDTYPE enmType, void **ppBackendData)
670{
671 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
672 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
673 int rc;
674 PRAWIMAGE pImage;
675
676 /* Check open flags. All valid flags are supported. */
677 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
678 AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);
679
680 pImage = (PRAWIMAGE)RTMemAllocZ(RT_UOFFSETOF(RAWIMAGE, RegionList.aRegions[1]));
681 if (RT_LIKELY(pImage))
682 {
683 pImage->pszFilename = pszFilename;
684 pImage->pStorage = NULL;
685 pImage->pVDIfsDisk = pVDIfsDisk;
686 pImage->pVDIfsImage = pVDIfsImage;
687
688 if (enmType == VDTYPE_OPTICAL_DISC)
689 pImage->cbSector = 2048;
690 else
691 pImage->cbSector = 512;
692
693 rc = rawOpenImage(pImage, uOpenFlags);
694 if (RT_SUCCESS(rc))
695 *ppBackendData = pImage;
696 else
697 RTMemFree(pImage);
698 }
699 else
700 rc = VERR_NO_MEMORY;
701
702 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
703 return rc;
704}
705
706/** @copydoc VDIMAGEBACKEND::pfnCreate */
707static DECLCALLBACK(int) rawCreate(const char *pszFilename, uint64_t cbSize,
708 unsigned uImageFlags, const char *pszComment,
709 PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
710 PCRTUUID pUuid, unsigned uOpenFlags,
711 unsigned uPercentStart, unsigned uPercentSpan,
712 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
713 PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
714 void **ppBackendData)
715{
716 RT_NOREF1(pUuid);
717 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",
718 pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
719
720 /* Check the VD container type. Yes, hard disk must be allowed, otherwise
721 * various tools using this backend for hard disk images will fail. */
722 if (enmType != VDTYPE_HDD && enmType != VDTYPE_OPTICAL_DISC && enmType != VDTYPE_FLOPPY)
723 return VERR_VD_INVALID_TYPE;
724
725 int rc = VINF_SUCCESS;
726 PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
727
728 /* Check arguments. */
729 AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
730 AssertReturn( VALID_PTR(pszFilename)
731 && *pszFilename
732 && VALID_PTR(pPCHSGeometry)
733 && VALID_PTR(pLCHSGeometry), VERR_INVALID_PARAMETER);
734
735 PRAWIMAGE pImage = (PRAWIMAGE)RTMemAllocZ(RT_UOFFSETOF(RAWIMAGE, RegionList.aRegions[1]));
736 if (RT_LIKELY(pImage))
737 {
738 pImage->pszFilename = pszFilename;
739 pImage->pStorage = NULL;
740 pImage->pVDIfsDisk = pVDIfsDisk;
741 pImage->pVDIfsImage = pVDIfsImage;
742
743 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
744 pPCHSGeometry, pLCHSGeometry, uOpenFlags,
745 pIfProgress, uPercentStart, uPercentSpan);
746 if (RT_SUCCESS(rc))
747 {
748 /* So far the image is opened in read/write mode. Make sure the
749 * image is opened in read-only mode if the caller requested that. */
750 if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
751 {
752 rawFreeImage(pImage, false);
753 rc = rawOpenImage(pImage, uOpenFlags);
754 }
755
756 if (RT_SUCCESS(rc))
757 *ppBackendData = pImage;
758 }
759
760 if (RT_FAILURE(rc))
761 RTMemFree(pImage);
762 }
763 else
764 rc = VERR_NO_MEMORY;
765
766 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
767 return rc;
768}
769
770/** @copydoc VDIMAGEBACKEND::pfnRename */
771static DECLCALLBACK(int) rawRename(void *pBackendData, const char *pszFilename)
772{
773 LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
774 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
775
776 AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
777
778 /* Close the image. */
779 int rc = rawFreeImage(pImage, false);
780 if (RT_SUCCESS(rc))
781 {
782 /* Rename the file. */
783 rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
784 if (RT_SUCCESS(rc))
785 {
786 /* Update pImage with the new information. */
787 pImage->pszFilename = pszFilename;
788
789 /* Open the old image with new name. */
790 rc = rawOpenImage(pImage, pImage->uOpenFlags);
791 }
792 else
793 {
794 /* The move failed, try to reopen the original image. */
795 int rc2 = rawOpenImage(pImage, pImage->uOpenFlags);
796 if (RT_FAILURE(rc2))
797 rc = rc2;
798 }
799 }
800
801 LogFlowFunc(("returns %Rrc\n", rc));
802 return rc;
803}
804
805/** @copydoc VDIMAGEBACKEND::pfnClose */
806static DECLCALLBACK(int) rawClose(void *pBackendData, bool fDelete)
807{
808 LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
809 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
810 int rc = rawFreeImage(pImage, fDelete);
811 RTMemFree(pImage);
812
813 LogFlowFunc(("returns %Rrc\n", rc));
814 return rc;
815}
816
817/** @copydoc VDIMAGEBACKEND::pfnRead */
818static DECLCALLBACK(int) rawRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
819 PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
820{
821 int rc = VINF_SUCCESS;
822 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
823
824 /* For sequential access do not allow to go back. */
825 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
826 && uOffset < pImage->offAccess)
827 {
828 *pcbActuallyRead = 0;
829 return VERR_INVALID_PARAMETER;
830 }
831
832 rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
833 pIoCtx, cbToRead);
834 if (RT_SUCCESS(rc))
835 {
836 *pcbActuallyRead = cbToRead;
837 pImage->offAccess = uOffset + cbToRead;
838 }
839
840 return rc;
841}
842
843/** @copydoc VDIMAGEBACKEND::pfnWrite */
844static DECLCALLBACK(int) rawWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
845 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
846 size_t *pcbPostRead, unsigned fWrite)
847{
848 RT_NOREF1(fWrite);
849 int rc = VINF_SUCCESS;
850 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
851
852 /* For sequential access do not allow to go back. */
853 if ( pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
854 && uOffset < pImage->offAccess)
855 {
856 *pcbWriteProcess = 0;
857 *pcbPostRead = 0;
858 *pcbPreRead = 0;
859 return VERR_INVALID_PARAMETER;
860 }
861
862 rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
863 pIoCtx, cbToWrite, NULL, NULL);
864 if (RT_SUCCESS(rc))
865 {
866 *pcbWriteProcess = cbToWrite;
867 *pcbPostRead = 0;
868 *pcbPreRead = 0;
869 pImage->offAccess = uOffset + cbToWrite;
870 }
871
872 return rc;
873}
874
875/** @copydoc VDIMAGEBACKEND::pfnFlush */
876static DECLCALLBACK(int) rawFlush(void *pBackendData, PVDIOCTX pIoCtx)
877{
878 int rc = VINF_SUCCESS;
879 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
880
881 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
882 rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx,
883 NULL, NULL);
884
885 return rc;
886}
887
888/** @copydoc VDIMAGEBACKEND::pfnGetVersion */
889static DECLCALLBACK(unsigned) rawGetVersion(void *pBackendData)
890{
891 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
892 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
893
894 AssertPtrReturn(pImage, 0);
895
896 return 1;
897}
898
899/** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
900static DECLCALLBACK(uint64_t) rawGetFileSize(void *pBackendData)
901{
902 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
903 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
904
905 AssertPtrReturn(pImage, 0);
906
907 uint64_t cbFile = 0;
908 if (pImage->pStorage)
909 {
910 int rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbFile);
911 if (RT_FAILURE(rc))
912 cbFile = 0; /* Make sure it is 0 */
913 }
914
915 LogFlowFunc(("returns %lld\n", cbFile));
916 return cbFile;
917}
918
919/** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
920static DECLCALLBACK(int) rawGetPCHSGeometry(void *pBackendData,
921 PVDGEOMETRY pPCHSGeometry)
922{
923 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
924 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
925 int rc = VINF_SUCCESS;
926
927 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
928
929 if (pImage->PCHSGeometry.cCylinders)
930 *pPCHSGeometry = pImage->PCHSGeometry;
931 else
932 rc = VERR_VD_GEOMETRY_NOT_SET;
933
934 LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
935 return rc;
936}
937
938/** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
939static DECLCALLBACK(int) rawSetPCHSGeometry(void *pBackendData,
940 PCVDGEOMETRY pPCHSGeometry)
941{
942 LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n",
943 pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
944 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
945 int rc = VINF_SUCCESS;
946
947 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
948
949 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
950 rc = VERR_VD_IMAGE_READ_ONLY;
951 else
952 pImage->PCHSGeometry = *pPCHSGeometry;
953
954 LogFlowFunc(("returns %Rrc\n", rc));
955 return rc;
956}
957
958/** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
959static DECLCALLBACK(int) rawGetLCHSGeometry(void *pBackendData,
960 PVDGEOMETRY pLCHSGeometry)
961{
962 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
963 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
964 int rc = VINF_SUCCESS;
965
966 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
967
968 if (pImage->LCHSGeometry.cCylinders)
969 *pLCHSGeometry = pImage->LCHSGeometry;
970 else
971 rc = VERR_VD_GEOMETRY_NOT_SET;
972
973 LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
974 return rc;
975}
976
977/** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
978static DECLCALLBACK(int) rawSetLCHSGeometry(void *pBackendData,
979 PCVDGEOMETRY pLCHSGeometry)
980{
981 LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n",
982 pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
983 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
984 int rc = VINF_SUCCESS;
985
986 AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
987
988 if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
989 rc = VERR_VD_IMAGE_READ_ONLY;
990 else
991 pImage->LCHSGeometry = *pLCHSGeometry;
992
993 LogFlowFunc(("returns %Rrc\n", rc));
994 return rc;
995}
996
997/** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
998static DECLCALLBACK(int) rawQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
999{
1000 LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
1001 PRAWIMAGE pThis = (PRAWIMAGE)pBackendData;
1002
1003 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
1004
1005 *ppRegionList = &pThis->RegionList;
1006 LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
1007 return VINF_SUCCESS;
1008}
1009
1010/** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
1011static DECLCALLBACK(void) rawRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
1012{
1013 RT_NOREF1(pRegionList);
1014 LogFlowFunc(("pBackendData=%#p pRegionList=%#p\n", pBackendData, pRegionList));
1015 PRAWIMAGE pThis = (PRAWIMAGE)pBackendData;
1016 AssertPtr(pThis); RT_NOREF(pThis);
1017
1018 /* Nothing to do here. */
1019}
1020
1021/** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
1022static DECLCALLBACK(unsigned) rawGetImageFlags(void *pBackendData)
1023{
1024 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1025 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1026
1027 AssertPtrReturn(pImage, 0);
1028
1029 LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
1030 return pImage->uImageFlags;
1031}
1032
1033/** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
1034static DECLCALLBACK(unsigned) rawGetOpenFlags(void *pBackendData)
1035{
1036 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
1037 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1038
1039 AssertPtrReturn(pImage, 0);
1040
1041 LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
1042 return pImage->uOpenFlags;
1043}
1044
1045/** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
1046static DECLCALLBACK(int) rawSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
1047{
1048 LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
1049 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1050 int rc = VINF_SUCCESS;
1051
1052 /* Image must be opened and the new flags must be valid. */
1053 if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
1054 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
1055 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
1056 rc = VERR_INVALID_PARAMETER;
1057 else
1058 {
1059 /* Implement this operation via reopening the image. */
1060 rc = rawFreeImage(pImage, false);
1061 if (RT_SUCCESS(rc))
1062 rc = rawOpenImage(pImage, uOpenFlags);
1063 }
1064
1065 LogFlowFunc(("returns %Rrc\n", rc));
1066 return rc;
1067}
1068
1069/** @copydoc VDIMAGEBACKEND::pfnGetComment */
1070VD_BACKEND_CALLBACK_GET_COMMENT_DEF_NOT_SUPPORTED(rawGetComment);
1071
1072/** @copydoc VDIMAGEBACKEND::pfnSetComment */
1073VD_BACKEND_CALLBACK_SET_COMMENT_DEF_NOT_SUPPORTED(rawSetComment, PRAWIMAGE);
1074
1075/** @copydoc VDIMAGEBACKEND::pfnGetUuid */
1076VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetUuid);
1077
1078/** @copydoc VDIMAGEBACKEND::pfnSetUuid */
1079VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetUuid, PRAWIMAGE);
1080
1081/** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
1082VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetModificationUuid);
1083
1084/** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
1085VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetModificationUuid, PRAWIMAGE);
1086
1087/** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
1088VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetParentUuid);
1089
1090/** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
1091VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetParentUuid, PRAWIMAGE);
1092
1093/** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
1094VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(rawGetParentModificationUuid);
1095
1096/** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
1097VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(rawSetParentModificationUuid, PRAWIMAGE);
1098
1099/** @copydoc VDIMAGEBACKEND::pfnDump */
1100static DECLCALLBACK(void) rawDump(void *pBackendData)
1101{
1102 PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
1103
1104 AssertPtrReturnVoid(pImage);
1105 vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
1106 pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
1107 pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
1108 pImage->cbSize / 512);
1109}
1110
1111
1112
1113const VDIMAGEBACKEND g_RawBackend =
1114{
1115 /* u32Version */
1116 VD_IMGBACKEND_VERSION,
1117 /* pszBackendName */
1118 "RAW",
1119 /* uBackendCaps */
1120 VD_CAP_CREATE_FIXED | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
1121 /* paFileExtensions */
1122 s_aRawFileExtensions,
1123 /* paConfigInfo */
1124 NULL,
1125 /* pfnProbe */
1126 rawProbe,
1127 /* pfnOpen */
1128 rawOpen,
1129 /* pfnCreate */
1130 rawCreate,
1131 /* pfnRename */
1132 rawRename,
1133 /* pfnClose */
1134 rawClose,
1135 /* pfnRead */
1136 rawRead,
1137 /* pfnWrite */
1138 rawWrite,
1139 /* pfnFlush */
1140 rawFlush,
1141 /* pfnDiscard */
1142 NULL,
1143 /* pfnGetVersion */
1144 rawGetVersion,
1145 /* pfnGetFileSize */
1146 rawGetFileSize,
1147 /* pfnGetPCHSGeometry */
1148 rawGetPCHSGeometry,
1149 /* pfnSetPCHSGeometry */
1150 rawSetPCHSGeometry,
1151 /* pfnGetLCHSGeometry */
1152 rawGetLCHSGeometry,
1153 /* pfnSetLCHSGeometry */
1154 rawSetLCHSGeometry,
1155 /* pfnQueryRegions */
1156 rawQueryRegions,
1157 /* pfnRegionListRelease */
1158 rawRegionListRelease,
1159 /* pfnGetImageFlags */
1160 rawGetImageFlags,
1161 /* pfnGetOpenFlags */
1162 rawGetOpenFlags,
1163 /* pfnSetOpenFlags */
1164 rawSetOpenFlags,
1165 /* pfnGetComment */
1166 rawGetComment,
1167 /* pfnSetComment */
1168 rawSetComment,
1169 /* pfnGetUuid */
1170 rawGetUuid,
1171 /* pfnSetUuid */
1172 rawSetUuid,
1173 /* pfnGetModificationUuid */
1174 rawGetModificationUuid,
1175 /* pfnSetModificationUuid */
1176 rawSetModificationUuid,
1177 /* pfnGetParentUuid */
1178 rawGetParentUuid,
1179 /* pfnSetParentUuid */
1180 rawSetParentUuid,
1181 /* pfnGetParentModificationUuid */
1182 rawGetParentModificationUuid,
1183 /* pfnSetParentModificationUuid */
1184 rawSetParentModificationUuid,
1185 /* pfnDump */
1186 rawDump,
1187 /* pfnGetTimestamp */
1188 NULL,
1189 /* pfnGetParentTimestamp */
1190 NULL,
1191 /* pfnSetParentTimestamp */
1192 NULL,
1193 /* pfnGetParentFilename */
1194 NULL,
1195 /* pfnSetParentFilename */
1196 NULL,
1197 /* pfnComposeLocation */
1198 genericFileComposeLocation,
1199 /* pfnComposeName */
1200 genericFileComposeName,
1201 /* pfnCompact */
1202 NULL,
1203 /* pfnResize */
1204 NULL,
1205 /* pfnRepair */
1206 NULL,
1207 /* pfnTraverseMetadata */
1208 NULL,
1209 /* u32VersionEnd */
1210 VD_IMGBACKEND_VERSION
1211};
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