VirtualBox

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

Last change on this file since 107712 was 107423, checked in by vboxsync, 5 weeks ago

Storage/RAW.cpp: Fix some parfait warnings, bugref:3409

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