VirtualBox

source: vbox/trunk/src/VBox/Storage/VISO.cpp@ 67981

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

VISO.cpp: Massage the probe returns.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.6 KB
Line 
1/* $Id: VISO.cpp 67761 2017-07-03 15:18:27Z vboxsync $ */
2/** @file
3 * VISO - Virtual ISO disk image, Core Code.
4 */
5
6/*
7 * Copyright (C) 2017 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
23#include <VBox/vd-plugin.h>
24#include <VBox/err.h>
25
26#include <VBox/log.h>
27//#include <VBox/scsiinline.h>
28#include <iprt/assert.h>
29#include <iprt/ctype.h>
30#include <iprt/fsisomaker.h>
31#include <iprt/getopt.h>
32#include <iprt/mem.h>
33#include <iprt/string.h>
34#include <iprt/uuid.h>
35
36#include "VDBackends.h"
37#include "VDBackendsInline.h"
38
39
40/*********************************************************************************************************************************
41* Defined Constants And Macros *
42*********************************************************************************************************************************/
43/** The maximum file size. */
44#if ARCH_BITS >= 64
45# define VISO_MAX_FILE_SIZE _32M
46#else
47# define VISO_MAX_FILE_SIZE _8M
48#endif
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54
55/**
56 * VBox ISO maker image instance.
57 */
58typedef struct VISOIMAGE
59{
60 /** The ISO maker output file handle.
61 * This is NIL if in VD_OPEN_FLAGS_INFO mode. */
62 RTVFSFILE hIsoFile;
63 /** The image size. */
64 uint64_t cbImage;
65 /** The UUID ofr the image. */
66 RTUUID Uuid;
67
68 /** Open flags passed by VD layer. */
69 uint32_t fOpenFlags;
70 /** Image name (for debug).
71 * Allocation follows the region list, no need to free. */
72 const char *pszFilename;
73
74 /** I/O interface. */
75 PVDINTERFACEIOINT pIfIo;
76 /** Error interface. */
77 PVDINTERFACEERROR pIfError;
78
79 /** Internal region list (variable size). */
80 VDREGIONLIST RegionList;
81} VISOIMAGE;
82/** Pointer to an VBox ISO make image instance. */
83typedef VISOIMAGE *PVISOIMAGE;
84
85
86/*********************************************************************************************************************************
87* Global Variables *
88*********************************************************************************************************************************/
89/** NULL-terminated array of supported file extensions. */
90static const VDFILEEXTENSION g_aVBoXIsoMakerFileExtensions[] =
91{
92 //{ "vbox-iso-maker", VDTYPE_OPTICAL_DISC }, - clumsy.
93 { "viso", VDTYPE_OPTICAL_DISC },
94 { NULL, VDTYPE_INVALID }
95};
96
97
98/**
99 * Parses the UUID that follows the marker argument.
100 *
101 * @returns IPRT status code.
102 * @param pszMarker The marker.
103 * @param pUuid Where to return the UUID.
104 */
105static int visoParseUuid(char *pszMarker, PRTUUID pUuid)
106{
107 /* Skip the marker. */
108 char ch;
109 while ( (ch = *pszMarker) != '\0'
110 && !RT_C_IS_SPACE(ch)
111 && ch != ':'
112 && ch != '=')
113 pszMarker++;
114
115 /* Skip chars before the value. */
116 if ( ch == ':'
117 || ch == '=')
118 ch = *++pszMarker;
119 else
120 while (RT_C_IS_SPACE(ch))
121 ch = *++pszMarker;
122 const char * const pszUuid = pszMarker;
123
124 /* Find the end of the UUID value. */
125 while ( ch != '\0'
126 && !RT_C_IS_SPACE(ch))
127 ch = *++pszMarker;
128
129 /* Validate the value (temporarily terminate the value string) */
130 *pszMarker = '\0';
131 int rc = RTUuidFromStr(pUuid, pszUuid);
132 if (RT_SUCCESS(rc))
133 {
134 *pszMarker = ch;
135 return VINF_SUCCESS;
136 }
137
138 /* Complain and return VERR_VD_IMAGE_CORRUPTED to indicate we've identified
139 the right image format, but the producer got something wrong. */
140 if (pszUuid != pszMarker)
141 LogRel(("visoParseUuid: Malformed UUID '%s': %Rrc\n", pszUuid, rc));
142 else
143 LogRel(("visoParseUuid: Empty/missing UUID!\n"));
144 *pszMarker = ch;
145
146 return VERR_VD_IMAGE_CORRUPTED;
147}
148
149
150static int visoProbeWorker(const char *pszFilename, PVDINTERFACEIOINT pIfIo, PRTUUID pUuid)
151{
152 PVDIOSTORAGE pStorage = NULL;
153 int rc = vdIfIoIntFileOpen(pIfIo, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &pStorage);
154 if (RT_SUCCESS(rc))
155 {
156 /*
157 * Read the first part of the file.
158 */
159 uint64_t cbFile = 0;
160 rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
161 if (RT_SUCCESS(rc))
162 {
163 char szChunk[_1K];
164 size_t cbToRead = (size_t)RT_MIN(sizeof(szChunk) - 1, cbFile);
165 rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0 /*off*/, szChunk, cbToRead);
166 if (RT_SUCCESS(rc))
167 {
168 szChunk[cbToRead] = '\0';
169
170 /*
171 * Skip leading spaces and check for the eye-catcher.
172 */
173 char *psz = szChunk;
174 while (RT_C_IS_SPACE(*psz))
175 psz++;
176 if (strncmp(psz, RT_STR_TUPLE("--iprt-iso-maker-file-marker")) == 0)
177 {
178 rc = visoParseUuid(psz, pUuid);
179 if (RT_SUCCESS(rc))
180 {
181 /*
182 * Check the file size.
183 */
184 if (cbFile <= VISO_MAX_FILE_SIZE)
185 rc = VINF_SUCCESS;
186 else
187 {
188 LogRel(("visoProbeWorker: VERR_VD_INVALID_SIZE - cbFile=%#RX64 cbMaxFile=%#RX64\n",
189 cbFile, (uint64_t)VISO_MAX_FILE_SIZE));
190 rc = VERR_VD_INVALID_SIZE;
191 }
192 }
193 else
194 rc = VERR_VD_IMAGE_CORRUPTED;
195 }
196 else
197 rc = VERR_VD_GEN_INVALID_HEADER;
198 }
199 }
200 vdIfIoIntFileClose(pIfIo, pStorage);
201 }
202 LogFlowFunc(("returns %Rrc\n", rc));
203 return rc;
204}
205
206/**
207 * @interface_method_impl{VDIMAGEBACKEND,pfnProbe}
208 */
209static DECLCALLBACK(int) visoProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
210{
211 /*
212 * Validate input.
213 */
214 AssertPtrReturn(penmType, VERR_INVALID_POINTER);
215 *penmType = VDTYPE_INVALID;
216
217 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
218 AssertReturn(*pszFilename, VERR_INVALID_POINTER);
219
220 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
221 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
222
223 RT_NOREF(pVDIfsDisk);
224
225 /*
226 * Share worker with visoOpen and visoSetFlags.
227 */
228 RTUUID UuidIgn;
229 int rc = visoProbeWorker(pszFilename, pIfIo, &UuidIgn);
230 if (RT_SUCCESS(rc))
231 *penmType = VDTYPE_OPTICAL_DISC;
232 else if (rc == VERR_VD_IMAGE_CORRUPTED || rc == VERR_VD_INVALID_SIZE)
233 *penmType = VDTYPE_OPTICAL_DISC;
234 else
235 rc = VERR_VD_GEN_INVALID_HEADER; /* Caller has strict, though undocument, status code expectations. */
236
237 LogFlowFunc(("returns %Rrc - *penmType=%d\n", rc, *penmType));
238 return rc;
239}
240
241
242/**
243 * Worker for visoOpen and visoSetOpenFlags that creates a VFS file for the ISO.
244 *
245 * This also updates cbImage and the Uuid members.
246 *
247 * @returns VBox status code.
248 * @param pThis The VISO image instance.
249 */
250static int visoOpenWorker(PVISOIMAGE pThis)
251{
252 /*
253 * Open the file and read it into memory.
254 */
255 PVDIOSTORAGE pStorage = NULL;
256 int rc = vdIfIoIntFileOpen(pThis->pIfIo, pThis->pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &pStorage);
257 if (RT_FAILURE(rc))
258 return rc;
259
260 /*
261 * Read the file into memory, prefixing it with a dummy command name.
262 */
263 uint64_t cbFile = 0;
264 rc = vdIfIoIntFileGetSize(pThis->pIfIo, pStorage, &cbFile);
265 if (RT_SUCCESS(rc))
266 {
267 if (cbFile <= VISO_MAX_FILE_SIZE)
268 {
269 static char const s_szCmdPrefix[] = "VBox-Iso-Maker ";
270
271 char *pszContent = (char *)RTMemTmpAlloc(sizeof(s_szCmdPrefix) + cbFile);
272 if (pszContent)
273 {
274 char *pszReadDst = &pszContent[sizeof(s_szCmdPrefix) - 1];
275 rc = vdIfIoIntFileReadSync(pThis->pIfIo, pStorage, 0 /*off*/, pszReadDst, (size_t)cbFile);
276 if (RT_SUCCESS(rc))
277 {
278 /*
279 * Check the file marker and get the UUID that follows it.
280 * Ignore leading blanks.
281 */
282 pszReadDst[(size_t)cbFile] = '\0';
283 memcpy(pszContent, s_szCmdPrefix, sizeof(s_szCmdPrefix) - 1);
284
285 while (RT_C_IS_SPACE(*pszReadDst))
286 pszReadDst++;
287 if (strncmp(pszReadDst, RT_STR_TUPLE("--iprt-iso-maker-file-marker")) == 0)
288 {
289 rc = visoParseUuid(pszReadDst, &pThis->Uuid);
290 if (RT_SUCCESS(rc))
291 {
292 /*
293 * Make sure it's valid UTF-8 before letting
294 */
295 rc = RTStrValidateEncodingEx(pszContent, sizeof(s_szCmdPrefix) + cbFile,
296 RTSTR_VALIDATE_ENCODING_EXACT_LENGTH
297 | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
298 if (RT_SUCCESS(rc))
299 {
300 /*
301 * Convert it into an argument vector.
302 * Free the content afterwards to reduce memory pressure.
303 */
304 uint32_t fGetOpt = strncmp(pszReadDst, RT_STR_TUPLE("--iprt-iso-maker-file-marker-ms")) != 0
305 ? RTGETOPTARGV_CNV_QUOTE_BOURNE_SH : RTGETOPTARGV_CNV_QUOTE_MS_CRT;
306 fGetOpt |= RTGETOPTARGV_CNV_MODIFY_INPUT;
307 char **papszArgs;
308 int cArgs;
309 rc = RTGetOptArgvFromString(&papszArgs, &cArgs, pszContent, fGetOpt, NULL);
310
311 if (RT_SUCCESS(rc))
312 {
313 /*
314 * Try instantiate the ISO image maker.
315 * Free the argument vector afterward to reduce memory pressure.
316 */
317 RTVFSFILE hVfsFile;
318 RTERRINFOSTATIC ErrInfo;
319 rc = RTFsIsoMakerCmdEx(cArgs, papszArgs, &hVfsFile, RTErrInfoInitStatic(&ErrInfo));
320
321 RTGetOptArgvFreeEx(papszArgs, fGetOpt);
322 papszArgs = NULL;
323
324 if (RT_SUCCESS(rc))
325 {
326 uint64_t cbImage;
327 rc = RTVfsFileGetSize(hVfsFile, &cbImage);
328 if (RT_SUCCESS(rc))
329 {
330 /*
331 * Update the state.
332 */
333 pThis->cbImage = cbImage;
334 pThis->RegionList.aRegions[0].cRegionBlocksOrBytes = cbImage;
335
336 pThis->hIsoFile = hVfsFile;
337 hVfsFile = NIL_RTVFSFILE;
338
339 rc = VINF_SUCCESS;
340 LogRel(("VISO: %'RU64 bytes (%#RX64) - %s\n", cbImage, cbImage, pThis->pszFilename));
341 }
342
343 RTVfsFileRelease(hVfsFile);
344 }
345 else if (RTErrInfoIsSet(&ErrInfo.Core))
346 {
347 LogRel(("visoOpenWorker: RTFsIsoMakerCmdEx failed: %Rrc - %s\n", rc, ErrInfo.Core.pszMsg));
348 vdIfError(pThis->pIfError, rc, RT_SRC_POS, "VISO: %s", ErrInfo.Core.pszMsg);
349 }
350 else
351 {
352 LogRel(("visoOpenWorker: RTFsIsoMakerCmdEx failed: %Rrc\n", rc));
353 vdIfError(pThis->pIfError, rc, RT_SRC_POS, "VISO: RTFsIsoMakerCmdEx failed: %Rrc", rc);
354 }
355 }
356 }
357 else
358 vdIfError(pThis->pIfError, rc, RT_SRC_POS, "VISO: Invalid file encoding");
359 }
360 }
361 else
362 rc = VERR_VD_GEN_INVALID_HEADER;
363 }
364
365 RTMemTmpFree(pszContent);
366 }
367 else
368 rc = VERR_NO_TMP_MEMORY;
369 }
370 else
371 {
372 LogRel(("visoOpen: VERR_VD_INVALID_SIZE - cbFile=%#RX64 cbMaxFile=%#RX64\n",
373 cbFile, (uint64_t)VISO_MAX_FILE_SIZE));
374 rc = VERR_VD_INVALID_SIZE;
375 }
376 }
377
378 vdIfIoIntFileClose(pThis->pIfIo, pStorage);
379 return rc;
380}
381
382
383/**
384 * @interface_method_impl{VDIMAGEBACKEND,pfnOpen}
385 */
386static DECLCALLBACK(int) visoOpen(const char *pszFilename, unsigned uOpenFlags, PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
387 VDTYPE enmType, void **ppBackendData)
388{
389 uint32_t const fOpenFlags = uOpenFlags;
390 LogFlowFunc(("pszFilename='%s' fOpenFlags=%#x pVDIfsDisk=%p pVDIfsImage=%p enmType=%u ppBackendData=%p\n",
391 pszFilename, fOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
392
393 /*
394 * Validate input.
395 */
396 AssertPtrReturn(ppBackendData, VERR_INVALID_POINTER);
397 *ppBackendData = NULL;
398
399 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
400 AssertReturn(*pszFilename, VERR_INVALID_POINTER);
401
402 AssertReturn(!(fOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_FLAGS);
403
404 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
405 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
406
407 PVDINTERFACEERROR pIfError = VDIfErrorGet(pVDIfsDisk);
408
409 AssertReturn(enmType == VDTYPE_OPTICAL_DISC, VERR_NOT_SUPPORTED);
410
411 /*
412 * Allocate and initialize the backend image instance data.
413 */
414 int rc;
415 size_t cbFilename = strlen(pszFilename) + 1;
416 PVISOIMAGE pThis = (PVISOIMAGE)RTMemAllocZ(RT_UOFFSETOF(VISOIMAGE, RegionList.aRegions[1]) + cbFilename);
417 if (pThis)
418 {
419 pThis->hIsoFile = NIL_RTVFSFILE;
420 pThis->cbImage = 0;
421 pThis->fOpenFlags = fOpenFlags;
422 pThis->pszFilename = (char *)memcpy(&pThis->RegionList.aRegions[1], pszFilename, cbFilename);
423 pThis->pIfIo = pIfIo;
424 pThis->pIfError = pIfError;
425
426 pThis->RegionList.fFlags = 0;
427 pThis->RegionList.cRegions = 1;
428 pThis->RegionList.aRegions[0].offRegion = 0;
429 pThis->RegionList.aRegions[0].cRegionBlocksOrBytes = 0;
430 pThis->RegionList.aRegions[0].cbBlock = 2048;
431 pThis->RegionList.aRegions[0].enmDataForm = VDREGIONDATAFORM_RAW;
432 pThis->RegionList.aRegions[0].enmMetadataForm = VDREGIONMETADATAFORM_NONE;
433 pThis->RegionList.aRegions[0].cbData = 2048;
434 pThis->RegionList.aRegions[0].cbMetadata = 0;
435
436 /*
437 * Only go all the way if this isn't an info query. Re-mastering an ISO
438 * can potentially be a lot of work and we don't want to go thru with it
439 * just because the GUI wants to display the image size.
440 */
441 if (!(fOpenFlags & VD_OPEN_FLAGS_INFO))
442 rc = visoOpenWorker(pThis);
443 else
444 rc = visoProbeWorker(pThis->pszFilename, pThis->pIfIo, &pThis->Uuid);
445 if (RT_SUCCESS(rc))
446 {
447 *ppBackendData = pThis;
448 LogFlowFunc(("returns VINF_SUCCESS (UUID=%RTuuid, pszFilename=%s)\n", &pThis->Uuid, pThis->pszFilename));
449 return VINF_SUCCESS;
450 }
451
452 RTMemFree(pThis);
453 }
454 else
455 rc = VERR_NO_MEMORY;
456 LogFlowFunc(("returns %Rrc\n", rc));
457 return rc;
458}
459
460
461/**
462 * @interface_method_impl{VDIMAGEBACKEND,pfnClose}
463 */
464static DECLCALLBACK(int) visoClose(void *pBackendData, bool fDelete)
465{
466 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
467 LogFlowFunc(("pThis=%p fDelete=%RTbool\n", pThis, fDelete));
468
469 if (pThis)
470 {
471 if (fDelete)
472 vdIfIoIntFileDelete(pThis->pIfIo, pThis->pszFilename);
473
474 if (pThis->hIsoFile != NIL_RTVFSFILE)
475 {
476 RTVfsFileRelease(pThis->hIsoFile);
477 pThis->hIsoFile = NIL_RTVFSFILE;
478 }
479
480 RTMemFree(pThis);
481 }
482
483 LogFlowFunc(("returns VINF_SUCCESS\n"));
484 return VINF_SUCCESS;
485}
486
487/**
488 * @interface_method_impl{VDIMAGEBACKEND,pfnRead}
489 */
490static DECLCALLBACK(int) visoRead(void *pBackendData, uint64_t uOffset, size_t cbToRead, PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
491{
492 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
493 uint64_t off = uOffset;
494 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
495 AssertReturn(pThis->hIsoFile != NIL_RTVFSFILE, VERR_VD_NOT_OPENED);
496 LogFlowFunc(("pThis=%p off=%#RX64 cbToRead=%#zx pIoCtx=%p pcbActuallyRead=%p\n", pThis, off, cbToRead, pIoCtx, pcbActuallyRead));
497
498 /*
499 * Check request.
500 */
501 AssertReturn( off < pThis->cbImage
502 || (off == pThis->cbImage && cbToRead == 0), VERR_EOF);
503
504 uint64_t cbLeftInImage = pThis->cbImage - off;
505 if (cbToRead >= cbLeftInImage)
506 cbToRead = cbLeftInImage; /* ASSUMES the caller can deal with this, given the pcbActuallyRead parameter... */
507
508 /*
509 * Work the I/O context using vdIfIoIntIoCtxSegArrayCreate.
510 */
511 int rc = VINF_SUCCESS;
512 size_t cbActuallyRead = 0;
513 while (cbToRead > 0)
514 {
515 RTSGSEG Seg;
516 unsigned cSegs = 1;
517 size_t cbThisRead = vdIfIoIntIoCtxSegArrayCreate(pThis->pIfIo, pIoCtx, &Seg, &cSegs, cbToRead);
518 AssertBreakStmt(cbThisRead != 0, rc = VERR_INTERNAL_ERROR_2);
519 Assert(cbThisRead == Seg.cbSeg);
520
521 rc = RTVfsFileReadAt(pThis->hIsoFile, off, Seg.pvSeg, cbThisRead, NULL);
522 AssertRCBreak(rc);
523
524 /* advance. */
525 cbActuallyRead += cbThisRead;
526 off += cbThisRead;
527 cbToRead -= cbThisRead;
528 }
529
530 *pcbActuallyRead = cbActuallyRead;
531 return rc;
532}
533
534/**
535 * @interface_method_impl{VDIMAGEBACKEND,pfnWrite}
536 */
537static DECLCALLBACK(int) visoWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
538 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
539 size_t *pcbPostRead, unsigned fWrite)
540{
541 RT_NOREF(uOffset, cbToWrite, pIoCtx, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite);
542 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
543 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
544 AssertReturn(pThis->hIsoFile != NIL_RTVFSFILE, VERR_VD_NOT_OPENED);
545 LogFlowFunc(("pThis=%p off=%#RX64 pIoCtx=%p cbToWrite=%#zx pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p -> VERR_VD_IMAGE_READ_ONLY\n",
546 pThis, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
547 return VERR_VD_IMAGE_READ_ONLY;
548}
549
550/**
551 * @interface_method_impl{VDIMAGEBACKEND,pfnFlush}
552 */
553static DECLCALLBACK(int) visoFlush(void *pBackendData, PVDIOCTX pIoCtx)
554{
555 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
556 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
557 AssertReturn(pThis->hIsoFile != NIL_RTVFSFILE, VERR_VD_NOT_OPENED);
558 RT_NOREF(pIoCtx);
559 return VINF_SUCCESS;
560}
561
562/**
563 * @interface_method_impl{VDIMAGEBACKEND,pfnGetVersion}
564 */
565static DECLCALLBACK(unsigned) visoGetVersion(void *pBackendData)
566{
567 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
568 AssertPtrReturn(pThis, 0);
569 LogFlowFunc(("pThis=%#p -> 1\n", pThis));
570 return 1;
571}
572
573/**
574 * @interface_method_impl{VDIMAGEBACKEND,pfnGetFileSize}
575 */
576static DECLCALLBACK(uint64_t) visoGetFileSize(void *pBackendData)
577{
578 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
579 AssertPtrReturn(pThis, 0);
580 LogFlowFunc(("pThis=%p -> %RX64 (%s)\n", pThis, pThis->cbImage, pThis->hIsoFile == NIL_RTVFSFILE ? "fake!" : "real"));
581 return pThis->cbImage;
582}
583
584/**
585 * @interface_method_impl{VDIMAGEBACKEND,pfnGetPCHSGeometry}
586 */
587static DECLCALLBACK(int) visoGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
588{
589 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
590 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
591 LogFlowFunc(("pThis=%p pPCHSGeometry=%p -> VERR_NOT_SUPPORTED\n", pThis, pPCHSGeometry));
592 RT_NOREF(pPCHSGeometry);
593 return VERR_NOT_SUPPORTED;
594}
595
596/**
597 * @interface_method_impl{VDIMAGEBACKEND,pfnSetPCHSGeometry}
598 */
599static DECLCALLBACK(int) visoSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
600{
601 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
602 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
603 LogFlowFunc(("pThis=%p pPCHSGeometry=%p:{%u/%u/%u} -> VERR_VD_IMAGE_READ_ONLY\n",
604 pThis, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
605 RT_NOREF(pPCHSGeometry);
606 return VERR_VD_IMAGE_READ_ONLY;
607}
608
609/**
610 * @interface_method_impl{VDIMAGEBACKEND,pfnGetLCHSGeometry}
611 */
612static DECLCALLBACK(int) visoGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
613{
614 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
615 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
616 LogFlowFunc(("pThis=%p pLCHSGeometry=%p -> VERR_NOT_SUPPORTED\n", pThis, pLCHSGeometry));
617 RT_NOREF(pLCHSGeometry);
618 return VERR_NOT_SUPPORTED;
619}
620
621/**
622 * @interface_method_impl{VDIMAGEBACKEND,pfnSetLCHSGeometry}
623 */
624static DECLCALLBACK(int) visoSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
625{
626 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
627 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
628 LogFlowFunc(("pThis=%p pLCHSGeometry=%p:{%u/%u/%u} -> VERR_VD_IMAGE_READ_ONLY\n",
629 pThis, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
630 RT_NOREF(pLCHSGeometry);
631 return VERR_VD_IMAGE_READ_ONLY;
632}
633
634/**
635 * @interface_method_impl{VDIMAGEBACKEND,pfnQueryRegions}
636 */
637static DECLCALLBACK(int) visoQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
638{
639 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
640 *ppRegionList = NULL;
641 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
642
643 *ppRegionList = &pThis->RegionList;
644 LogFlowFunc(("returns VINF_SUCCESS (one region: 0 LB %RX64; pThis=%p)\n", pThis->RegionList.aRegions[0].cbData, pThis));
645 return VINF_SUCCESS;
646}
647
648/**
649 * @interface_method_impl{VDIMAGEBACKEND,pfnRegionListRelease}
650 */
651static DECLCALLBACK(void) visoRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
652{
653 /* Nothing to do here. Just assert the input to avoid unused parameter warnings. */
654 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
655 LogFlowFunc(("pThis=%p pRegionList=%p\n", pThis, pRegionList));
656 AssertPtrReturnVoid(pThis);
657 AssertReturnVoid(pRegionList == &pThis->RegionList || pRegionList == 0);
658}
659
660/**
661 * @interface_method_impl{VDIMAGEBACKEND,pfnGetImageFlags}
662 */
663static DECLCALLBACK(unsigned) visoGetImageFlags(void *pBackendData)
664{
665 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
666 LogFlowFunc(("pThis=%p -> VD_IMAGE_FLAGS_NONE\n", pThis));
667 AssertPtrReturn(pThis, VD_IMAGE_FLAGS_NONE);
668 return VD_IMAGE_FLAGS_NONE;
669}
670
671/**
672 * @interface_method_impl{VDIMAGEBACKEND,pfnGetOpenFlags}
673 */
674static DECLCALLBACK(unsigned) visoGetOpenFlags(void *pBackendData)
675{
676 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
677 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
678 AssertPtrReturn(pThis, 0);
679
680 LogFlowFunc(("returns %#x\n", pThis->fOpenFlags));
681 return pThis->fOpenFlags;
682}
683
684/**
685 * @interface_method_impl{VDIMAGEBACKEND,pfnSetOpenFlags}
686 */
687static DECLCALLBACK(int) visoSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
688{
689 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
690 LogFlowFunc(("pThis=%p fOpenFlags=%#x\n", pThis, uOpenFlags));
691
692 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
693 uint32_t const fSupported = VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
694 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
695 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS;
696 AssertMsgReturn(!(uOpenFlags & ~fSupported), ("fOpenFlags=%#x\n", uOpenFlags), VERR_INVALID_FLAGS);
697
698 /*
699 * Only react if we switch from VD_OPEN_FLAGS_INFO to non-VD_OPEN_FLAGS_INFO mode,
700 * becuase that means we need to open the image.
701 */
702 if ( (pThis->fOpenFlags & VD_OPEN_FLAGS_INFO)
703 && !(uOpenFlags & VD_OPEN_FLAGS_INFO)
704 && pThis->hIsoFile == NIL_RTVFSFILE)
705 {
706 int rc = visoOpenWorker(pThis);
707 if (RT_FAILURE(rc))
708 {
709 LogFlowFunc(("returns %Rrc\n", rc));
710 return rc;
711 }
712 }
713
714 /*
715 * Update the flags.
716 */
717 pThis->fOpenFlags &= ~fSupported;
718 pThis->fOpenFlags |= fSupported & uOpenFlags;
719 pThis->fOpenFlags |= VD_OPEN_FLAGS_READONLY;
720 if (pThis->hIsoFile != NIL_RTVFSFILE)
721 pThis->fOpenFlags &= ~VD_OPEN_FLAGS_INFO;
722
723 return VINF_SUCCESS;
724}
725
726#define uOpenFlags fOpenFlags /* sigh */
727
728/**
729 * @interface_method_impl{VDIMAGEBACKEND,pfnGetComment}
730 */
731VD_BACKEND_CALLBACK_GET_COMMENT_DEF_NOT_SUPPORTED(visoGetComment);
732
733/**
734 * @interface_method_impl{VDIMAGEBACKEND,pfnSetComment}
735 */
736VD_BACKEND_CALLBACK_SET_COMMENT_DEF_NOT_SUPPORTED(visoSetComment, PVISOIMAGE);
737
738/**
739 * @interface_method_impl{VDIMAGEBACKEND,pfnGetUuid}
740 */
741static DECLCALLBACK(int) visoGetUuid(void *pBackendData, PRTUUID pUuid)
742{
743 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
744 *pUuid = pThis->Uuid;
745 LogFlowFunc(("returns VIF_SUCCESS (%RTuuid)\n", pUuid));
746 return VINF_SUCCESS;
747}
748
749/**
750 * @interface_method_impl{VDIMAGEBACKEND,pfnSetUuid}
751 */
752VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetUuid, PVISOIMAGE);
753
754/**
755 * @interface_method_impl{VDIMAGEBACKEND,pfnGetModificationUuid}
756 */
757VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(visoGetModificationUuid);
758
759/**
760 * @interface_method_impl{VDIMAGEBACKEND,pfnSetModificationUuid}
761 */
762VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetModificationUuid, PVISOIMAGE);
763
764/**
765 * @interface_method_impl{VDIMAGEBACKEND,pfnGetParentUuid}
766 */
767VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(visoGetParentUuid);
768
769/**
770 * @interface_method_impl{VDIMAGEBACKEND,pfnSetParentUuid}
771 */
772VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetParentUuid, PVISOIMAGE);
773
774/**
775 * @interface_method_impl{VDIMAGEBACKEND,pfnGetParentModificationUuid}
776 */
777VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(visoGetParentModificationUuid);
778
779/**
780 * @interface_method_impl{VDIMAGEBACKEND,pfnSetParentModificationUuid}
781 */
782VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetParentModificationUuid, PVISOIMAGE);
783
784#undef uOpenFlags
785
786/**
787 * @interface_method_impl{VDIMAGEBACKEND,pfnDump}
788 */
789static DECLCALLBACK(void) visoDump(void *pBackendData)
790{
791 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
792 AssertPtrReturnVoid(pThis);
793
794 vdIfErrorMessage(pThis->pIfError, "Dumping CUE image '%s' fOpenFlags=%x cbImage=%#RX64\n",
795 pThis->pszFilename, pThis->fOpenFlags, pThis->cbImage);
796}
797
798
799
800/**
801 * VBox ISO maker backend.
802 */
803const VDIMAGEBACKEND g_VBoxIsoMakerBackend =
804{
805 /* u32Version */
806 VD_IMGBACKEND_VERSION,
807 /* pszBackendName */
808 "VBoxIsoMaker",
809 /* uBackendCaps */
810 VD_CAP_FILE,
811 /* paFileExtensions */
812 g_aVBoXIsoMakerFileExtensions,
813 /* paConfigInfo */
814 NULL,
815 /* pfnProbe */
816 visoProbe,
817 /* pfnOpen */
818 visoOpen,
819 /* pfnCreate */
820 NULL,
821 /* pfnRename */
822 NULL,
823 /* pfnClose */
824 visoClose,
825 /* pfnRead */
826 visoRead,
827 /* pfnWrite */
828 visoWrite,
829 /* pfnFlush */
830 visoFlush,
831 /* pfnDiscard */
832 NULL,
833 /* pfnGetVersion */
834 visoGetVersion,
835 /* pfnGetFileSize */
836 visoGetFileSize,
837 /* pfnGetPCHSGeometry */
838 visoGetPCHSGeometry,
839 /* pfnSetPCHSGeometry */
840 visoSetPCHSGeometry,
841 /* pfnGetLCHSGeometry */
842 visoGetLCHSGeometry,
843 /* pfnSetLCHSGeometry */
844 visoSetLCHSGeometry,
845 /* pfnQueryRegions */
846 visoQueryRegions,
847 /* pfnRegionListRelease */
848 visoRegionListRelease,
849 /* pfnGetImageFlags */
850 visoGetImageFlags,
851 /* pfnGetOpenFlags */
852 visoGetOpenFlags,
853 /* pfnSetOpenFlags */
854 visoSetOpenFlags,
855 /* pfnGetComment */
856 visoGetComment,
857 /* pfnSetComment */
858 visoSetComment,
859 /* pfnGetUuid */
860 visoGetUuid,
861 /* pfnSetUuid */
862 visoSetUuid,
863 /* pfnGetModificationUuid */
864 visoGetModificationUuid,
865 /* pfnSetModificationUuid */
866 visoSetModificationUuid,
867 /* pfnGetParentUuid */
868 visoGetParentUuid,
869 /* pfnSetParentUuid */
870 visoSetParentUuid,
871 /* pfnGetParentModificationUuid */
872 visoGetParentModificationUuid,
873 /* pfnSetParentModificationUuid */
874 visoSetParentModificationUuid,
875 /* pfnDump */
876 visoDump,
877 /* pfnGetTimestamp */
878 NULL,
879 /* pfnGetParentTimestamp */
880 NULL,
881 /* pfnSetParentTimestamp */
882 NULL,
883 /* pfnGetParentFilename */
884 NULL,
885 /* pfnSetParentFilename */
886 NULL,
887 /* pfnComposeLocation */
888 genericFileComposeLocation,
889 /* pfnComposeName */
890 genericFileComposeName,
891 /* pfnCompact */
892 NULL,
893 /* pfnResize */
894 NULL,
895 /* pfnRepair */
896 NULL,
897 /* pfnTraverseMetadata */
898 NULL,
899 /* u32VersionEnd */
900 VD_IMGBACKEND_VERSION
901};
902
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use