VirtualBox

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

Last change on this file since 82781 was 79965, checked in by vboxsync, 5 years ago

Storage: Added a desired format parameter to VDGetFormat() so Main can pass along the device type. Bumped the RAW backend down after the CUE and VISO to prevent (impossible) mixups of tiny files. Extended rawProbe() to look for a valid ISO-9660/UDF descriptor sequence on the image if the caller doesn't say it should be a floppy or hdd, only if that fail go by the extension. Note! the pfnProbe callback should probably get a score return parameter to indicate how confient the backend is about the probe result, as this would prevent the RAW backend from accidentally grabbing images which belongs to a plug-in. bugref:9151

  • 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 79965 2019-07-24 20:32:32Z 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#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.

© 2023 Oracle
ContactPrivacy policyTerms of Use