VirtualBox

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

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

VISO: Another LogRel.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.3 KB
Line 
1/* $Id: VISO.cpp 67603 2017-06-26 12:00:07Z 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 }
194 else
195 rc = VERR_VD_GEN_INVALID_HEADER;
196 }
197 }
198 vdIfIoIntFileClose(pIfIo, pStorage);
199 }
200 LogFlowFunc(("returns %Rrc\n", rc));
201 return rc;
202}
203
204/**
205 * @interface_method_impl{VDIMAGEBACKEND,pfnProbe}
206 */
207static DECLCALLBACK(int) visoProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, VDTYPE *penmType)
208{
209 /*
210 * Validate input.
211 */
212 AssertPtrReturn(penmType, VERR_INVALID_POINTER);
213 *penmType = VDTYPE_INVALID;
214
215 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
216 AssertReturn(*pszFilename, VERR_INVALID_POINTER);
217
218 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
219 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
220
221 RT_NOREF(pVDIfsDisk);
222
223 /*
224 * Share worker with visoOpen and visoSetFlags.
225 */
226 RTUUID UuidIgn;
227 int rc = visoProbeWorker(pszFilename, pIfIo, &UuidIgn);
228 if (RT_SUCCESS(rc))
229 *penmType = VDTYPE_OPTICAL_DISC;
230
231 LogFlowFunc(("returns %Rrc - *penmType=%d\n", rc, *penmType));
232 return rc;
233}
234
235
236/**
237 * Worker for visoOpen and visoSetOpenFlags that creates a VFS file for the ISO.
238 *
239 * This also updates cbImage and the Uuid members.
240 *
241 * @returns VBox status code.
242 * @param pThis The VISO image instance.
243 */
244static int visoOpenWorker(PVISOIMAGE pThis)
245{
246 /*
247 * Open the file and read it into memory.
248 */
249 PVDIOSTORAGE pStorage = NULL;
250 int rc = vdIfIoIntFileOpen(pThis->pIfIo, pThis->pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &pStorage);
251 if (RT_FAILURE(rc))
252 return rc;
253
254 /*
255 * Read the file into memory, prefixing it with a dummy command name.
256 */
257 uint64_t cbFile = 0;
258 rc = vdIfIoIntFileGetSize(pThis->pIfIo, pStorage, &cbFile);
259 if (RT_SUCCESS(rc))
260 {
261 if (cbFile <= VISO_MAX_FILE_SIZE)
262 {
263 static char const s_szCmdPrefix[] = "VBox-Iso-Maker ";
264
265 char *pszContent = (char *)RTMemTmpAlloc(sizeof(s_szCmdPrefix) + cbFile);
266 if (pszContent)
267 {
268 char *pszReadDst = &pszContent[sizeof(s_szCmdPrefix) - 1];
269 rc = vdIfIoIntFileReadSync(pThis->pIfIo, pStorage, 0 /*off*/, pszReadDst, (size_t)cbFile);
270 if (RT_SUCCESS(rc))
271 {
272 /*
273 * Check the file marker and get the UUID that follows it.
274 * Ignore leading blanks.
275 */
276 pszReadDst[(size_t)cbFile] = '\0';
277 memcpy(pszContent, s_szCmdPrefix, sizeof(s_szCmdPrefix) - 1);
278
279 while (RT_C_IS_SPACE(*pszReadDst))
280 pszReadDst++;
281 if (strncmp(pszReadDst, RT_STR_TUPLE("--iprt-iso-maker-file-marker")) == 0)
282 {
283 rc = visoParseUuid(pszReadDst, &pThis->Uuid);
284 if (RT_SUCCESS(rc))
285 {
286 /*
287 * Make sure it's valid UTF-8 before letting
288 */
289 rc = RTStrValidateEncodingEx(pszContent, sizeof(s_szCmdPrefix) + cbFile,
290 RTSTR_VALIDATE_ENCODING_EXACT_LENGTH
291 | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
292 if (RT_SUCCESS(rc))
293 {
294 /*
295 * Convert it into an argument vector.
296 * Free the content afterwards to reduce memory pressure.
297 */
298 uint32_t fGetOpt = strncmp(pszReadDst, RT_STR_TUPLE("--iprt-iso-maker-file-marker-ms")) != 0
299 ? RTGETOPTARGV_CNV_QUOTE_BOURNE_SH : RTGETOPTARGV_CNV_QUOTE_MS_CRT;
300 fGetOpt |= RTGETOPTARGV_CNV_MODIFY_INPUT;
301 char **papszArgs;
302 int cArgs;
303 rc = RTGetOptArgvFromString(&papszArgs, &cArgs, pszContent, fGetOpt, NULL);
304
305 if (RT_SUCCESS(rc))
306 {
307 /*
308 * Try instantiate the ISO image maker.
309 * Free the argument vector afterward to reduce memory pressure.
310 */
311 RTVFSFILE hVfsFile;
312 RTERRINFOSTATIC ErrInfo;
313 rc = RTFsIsoMakerCmdEx(cArgs, papszArgs, &hVfsFile, RTErrInfoInitStatic(&ErrInfo));
314
315 RTGetOptArgvFreeEx(papszArgs, fGetOpt);
316 papszArgs = NULL;
317
318 if (RT_SUCCESS(rc))
319 {
320 uint64_t cbImage;
321 rc = RTVfsFileGetSize(hVfsFile, &cbImage);
322 if (RT_SUCCESS(rc))
323 {
324 /*
325 * Update the state.
326 */
327 pThis->cbImage = cbImage;
328 pThis->RegionList.aRegions[0].cRegionBlocksOrBytes = cbImage;
329
330 pThis->hIsoFile = hVfsFile;
331 hVfsFile = NIL_RTVFSFILE;
332
333 rc = VINF_SUCCESS;
334 LogRel(("VISO: %'RU64 bytes (%#RX64) - %s\n", cbImage, cbImage, pThis->pszFilename));
335 }
336
337 RTVfsFileRelease(hVfsFile);
338 }
339 else if (RTErrInfoIsSet(&ErrInfo.Core))
340 {
341 LogRel(("visoOpenWorker: RTFsIsoMakerCmdEx failed: %Rrc - %s\n", rc, ErrInfo.Core.pszMsg));
342 vdIfError(pThis->pIfError, rc, RT_SRC_POS, "VISO: %s", ErrInfo.Core.pszMsg);
343 }
344 else
345 {
346 LogRel(("visoOpenWorker: RTFsIsoMakerCmdEx failed: %Rrc\n", rc));
347 vdIfError(pThis->pIfError, rc, RT_SRC_POS, "VISO: RTFsIsoMakerCmdEx failed: %Rrc", rc);
348 }
349 }
350 }
351 else
352 vdIfError(pThis->pIfError, rc, RT_SRC_POS, "VISO: Invalid file encoding");
353 }
354 }
355 else
356 rc = VERR_VD_GEN_INVALID_HEADER;
357 }
358
359 RTMemTmpFree(pszContent);
360 }
361 else
362 rc = VERR_NO_TMP_MEMORY;
363 }
364 else
365 {
366 LogRel(("visoOpen: VERR_VD_INVALID_SIZE - cbFile=%#RX64 cbMaxFile=%#RX64\n",
367 cbFile, (uint64_t)VISO_MAX_FILE_SIZE));
368 rc = VERR_VD_INVALID_SIZE;
369 }
370 }
371
372 vdIfIoIntFileClose(pThis->pIfIo, pStorage);
373 return rc;
374}
375
376
377/**
378 * @interface_method_impl{VDIMAGEBACKEND,pfnOpen}
379 */
380static DECLCALLBACK(int) visoOpen(const char *pszFilename, unsigned uOpenFlags, PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
381 VDTYPE enmType, void **ppBackendData)
382{
383 uint32_t const fOpenFlags = uOpenFlags;
384 LogFlowFunc(("pszFilename='%s' fOpenFlags=%#x pVDIfsDisk=%p pVDIfsImage=%p enmType=%u ppBackendData=%p\n",
385 pszFilename, fOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
386
387 /*
388 * Validate input.
389 */
390 AssertPtrReturn(ppBackendData, VERR_INVALID_POINTER);
391 *ppBackendData = NULL;
392
393 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
394 AssertReturn(*pszFilename, VERR_INVALID_POINTER);
395
396 AssertReturn(!(fOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_FLAGS);
397
398 PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
399 AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
400
401 PVDINTERFACEERROR pIfError = VDIfErrorGet(pVDIfsDisk);
402
403 AssertReturn(enmType == VDTYPE_OPTICAL_DISC, VERR_NOT_SUPPORTED);
404
405 /*
406 * Allocate and initialize the backend image instance data.
407 */
408 int rc;
409 size_t cbFilename = strlen(pszFilename) + 1;
410 PVISOIMAGE pThis = (PVISOIMAGE)RTMemAllocZ(RT_UOFFSETOF(VISOIMAGE, RegionList.aRegions[1]) + cbFilename);
411 if (pThis)
412 {
413 pThis->hIsoFile = NIL_RTVFSFILE;
414 pThis->cbImage = 0;
415 pThis->fOpenFlags = fOpenFlags;
416 pThis->pszFilename = (char *)memcpy(&pThis->RegionList.aRegions[1], pszFilename, cbFilename);
417 pThis->pIfIo = pIfIo;
418 pThis->pIfError = pIfError;
419
420 pThis->RegionList.fFlags = 0;
421 pThis->RegionList.cRegions = 1;
422 pThis->RegionList.aRegions[0].offRegion = 0;
423 pThis->RegionList.aRegions[0].cRegionBlocksOrBytes = 0;
424 pThis->RegionList.aRegions[0].cbBlock = 2048;
425 pThis->RegionList.aRegions[0].enmDataForm = VDREGIONDATAFORM_RAW;
426 pThis->RegionList.aRegions[0].enmMetadataForm = VDREGIONMETADATAFORM_NONE;
427 pThis->RegionList.aRegions[0].cbData = 2048;
428 pThis->RegionList.aRegions[0].cbMetadata = 0;
429
430 /*
431 * Only go all the way if this isn't an info query. Re-mastering an ISO
432 * can potentially be a lot of work and we don't want to go thru with it
433 * just because the GUI wants to display the image size.
434 */
435 if (!(fOpenFlags & VD_OPEN_FLAGS_INFO))
436 rc = visoOpenWorker(pThis);
437 else
438 rc = visoProbeWorker(pThis->pszFilename, pThis->pIfIo, &pThis->Uuid);
439 if (RT_SUCCESS(rc))
440 {
441 *ppBackendData = pThis;
442 LogFlowFunc(("returns VINF_SUCCESS (UUID=%RTuuid, pszFilename=%s)\n", &pThis->Uuid, pThis->pszFilename));
443 return VINF_SUCCESS;
444 }
445
446 RTMemFree(pThis);
447 }
448 else
449 rc = VERR_NO_MEMORY;
450 LogFlowFunc(("returns %Rrc\n", rc));
451 return rc;
452}
453
454
455/**
456 * @interface_method_impl{VDIMAGEBACKEND,pfnClose}
457 */
458static DECLCALLBACK(int) visoClose(void *pBackendData, bool fDelete)
459{
460 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
461 LogFlowFunc(("pThis=%p fDelete=%RTbool\n", pThis, fDelete));
462
463 if (pThis)
464 {
465 if (fDelete)
466 vdIfIoIntFileDelete(pThis->pIfIo, pThis->pszFilename);
467
468 if (pThis->hIsoFile != NIL_RTVFSFILE)
469 {
470 RTVfsFileRelease(pThis->hIsoFile);
471 pThis->hIsoFile = NIL_RTVFSFILE;
472 }
473
474 RTMemFree(pThis);
475 }
476
477 LogFlowFunc(("returns VINF_SUCCESS\n"));
478 return VINF_SUCCESS;
479}
480
481/**
482 * @interface_method_impl{VDIMAGEBACKEND,pfnRead}
483 */
484static DECLCALLBACK(int) visoRead(void *pBackendData, uint64_t uOffset, size_t cbToRead, PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
485{
486 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
487 uint64_t off = uOffset;
488 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
489 AssertReturn(pThis->hIsoFile != NIL_RTVFSFILE, VERR_VD_NOT_OPENED);
490 LogFlowFunc(("pThis=%p off=%#RX64 cbToRead=%#zx pIoCtx=%p pcbActuallyRead=%p\n", pThis, off, cbToRead, pIoCtx, pcbActuallyRead));
491
492 /*
493 * Check request.
494 */
495 AssertReturn( off < pThis->cbImage
496 || (off == pThis->cbImage && cbToRead == 0), VERR_EOF);
497
498 uint64_t cbLeftInImage = pThis->cbImage - off;
499 if (cbToRead >= cbLeftInImage)
500 cbToRead = cbLeftInImage; /* ASSUMES the caller can deal with this, given the pcbActuallyRead parameter... */
501
502 /*
503 * Work the I/O context using vdIfIoIntIoCtxSegArrayCreate.
504 */
505 int rc = VINF_SUCCESS;
506 size_t cbActuallyRead = 0;
507 while (cbToRead > 0)
508 {
509 RTSGSEG Seg;
510 unsigned cSegs = 1;
511 size_t cbThisRead = vdIfIoIntIoCtxSegArrayCreate(pThis->pIfIo, pIoCtx, &Seg, &cSegs, cbToRead);
512 AssertBreakStmt(cbThisRead != 0, rc = VERR_INTERNAL_ERROR_2);
513 Assert(cbThisRead == Seg.cbSeg);
514
515 rc = RTVfsFileReadAt(pThis->hIsoFile, off, Seg.pvSeg, cbThisRead, NULL);
516 AssertRCBreak(rc);
517
518 /* advance. */
519 cbActuallyRead += cbThisRead;
520 off += cbThisRead;
521 cbToRead -= cbThisRead;
522 }
523
524 *pcbActuallyRead = cbActuallyRead;
525 return rc;
526}
527
528/**
529 * @interface_method_impl{VDIMAGEBACKEND,pfnWrite}
530 */
531static DECLCALLBACK(int) visoWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
532 PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
533 size_t *pcbPostRead, unsigned fWrite)
534{
535 RT_NOREF(uOffset, cbToWrite, pIoCtx, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite);
536 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
537 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
538 AssertReturn(pThis->hIsoFile != NIL_RTVFSFILE, VERR_VD_NOT_OPENED);
539 LogFlowFunc(("pThis=%p off=%#RX64 pIoCtx=%p cbToWrite=%#zx pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p -> VERR_VD_IMAGE_READ_ONLY\n",
540 pThis, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
541 return VERR_VD_IMAGE_READ_ONLY;
542}
543
544/**
545 * @interface_method_impl{VDIMAGEBACKEND,pfnFlush}
546 */
547static DECLCALLBACK(int) visoFlush(void *pBackendData, PVDIOCTX pIoCtx)
548{
549 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
550 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
551 AssertReturn(pThis->hIsoFile != NIL_RTVFSFILE, VERR_VD_NOT_OPENED);
552 RT_NOREF(pIoCtx);
553 return VINF_SUCCESS;
554}
555
556/**
557 * @interface_method_impl{VDIMAGEBACKEND,pfnGetVersion}
558 */
559static DECLCALLBACK(unsigned) visoGetVersion(void *pBackendData)
560{
561 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
562 AssertPtrReturn(pThis, 0);
563 LogFlowFunc(("pThis=%#p -> 1\n", pThis));
564 return 1;
565}
566
567/**
568 * @interface_method_impl{VDIMAGEBACKEND,pfnGetFileSize}
569 */
570static DECLCALLBACK(uint64_t) visoGetFileSize(void *pBackendData)
571{
572 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
573 AssertPtrReturn(pThis, 0);
574 LogFlowFunc(("pThis=%p -> %RX64 (%s)\n", pThis, pThis->cbImage, pThis->hIsoFile == NIL_RTVFSFILE ? "fake!" : "real"));
575 return pThis->cbImage;
576}
577
578/**
579 * @interface_method_impl{VDIMAGEBACKEND,pfnGetPCHSGeometry}
580 */
581static DECLCALLBACK(int) visoGetPCHSGeometry(void *pBackendData, PVDGEOMETRY pPCHSGeometry)
582{
583 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
584 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
585 LogFlowFunc(("pThis=%p pPCHSGeometry=%p -> VERR_NOT_SUPPORTED\n", pThis, pPCHSGeometry));
586 RT_NOREF(pPCHSGeometry);
587 return VERR_NOT_SUPPORTED;
588}
589
590/**
591 * @interface_method_impl{VDIMAGEBACKEND,pfnSetPCHSGeometry}
592 */
593static DECLCALLBACK(int) visoSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
594{
595 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
596 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
597 LogFlowFunc(("pThis=%p pPCHSGeometry=%p:{%u/%u/%u} -> VERR_VD_IMAGE_READ_ONLY\n",
598 pThis, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
599 RT_NOREF(pPCHSGeometry);
600 return VERR_VD_IMAGE_READ_ONLY;
601}
602
603/**
604 * @interface_method_impl{VDIMAGEBACKEND,pfnGetLCHSGeometry}
605 */
606static DECLCALLBACK(int) visoGetLCHSGeometry(void *pBackendData, PVDGEOMETRY pLCHSGeometry)
607{
608 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
609 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
610 LogFlowFunc(("pThis=%p pLCHSGeometry=%p -> VERR_NOT_SUPPORTED\n", pThis, pLCHSGeometry));
611 RT_NOREF(pLCHSGeometry);
612 return VERR_NOT_SUPPORTED;
613}
614
615/**
616 * @interface_method_impl{VDIMAGEBACKEND,pfnSetLCHSGeometry}
617 */
618static DECLCALLBACK(int) visoSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
619{
620 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
621 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
622 LogFlowFunc(("pThis=%p pLCHSGeometry=%p:{%u/%u/%u} -> VERR_VD_IMAGE_READ_ONLY\n",
623 pThis, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
624 RT_NOREF(pLCHSGeometry);
625 return VERR_VD_IMAGE_READ_ONLY;
626}
627
628/**
629 * @interface_method_impl{VDIMAGEBACKEND,pfnQueryRegions}
630 */
631static DECLCALLBACK(int) visoQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
632{
633 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
634 *ppRegionList = NULL;
635 AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
636
637 *ppRegionList = &pThis->RegionList;
638 LogFlowFunc(("returns VINF_SUCCESS (one region: 0 LB %RX64; pThis=%p)\n", pThis->RegionList.aRegions[0].cbData, pThis));
639 return VINF_SUCCESS;
640}
641
642/**
643 * @interface_method_impl{VDIMAGEBACKEND,pfnRegionListRelease}
644 */
645static DECLCALLBACK(void) visoRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
646{
647 /* Nothing to do here. Just assert the input to avoid unused parameter warnings. */
648 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
649 LogFlowFunc(("pThis=%p pRegionList=%p\n", pThis, pRegionList));
650 AssertPtrReturnVoid(pThis);
651 AssertReturnVoid(pRegionList == &pThis->RegionList || pRegionList == 0);
652}
653
654/**
655 * @interface_method_impl{VDIMAGEBACKEND,pfnGetImageFlags}
656 */
657static DECLCALLBACK(unsigned) visoGetImageFlags(void *pBackendData)
658{
659 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
660 LogFlowFunc(("pThis=%p -> VD_IMAGE_FLAGS_NONE\n", pThis));
661 AssertPtrReturn(pThis, VD_IMAGE_FLAGS_NONE);
662 return VD_IMAGE_FLAGS_NONE;
663}
664
665/**
666 * @interface_method_impl{VDIMAGEBACKEND,pfnGetOpenFlags}
667 */
668static DECLCALLBACK(unsigned) visoGetOpenFlags(void *pBackendData)
669{
670 LogFlowFunc(("pBackendData=%#p\n", pBackendData));
671 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
672 AssertPtrReturn(pThis, 0);
673
674 LogFlowFunc(("returns %#x\n", pThis->fOpenFlags));
675 return pThis->fOpenFlags;
676}
677
678/**
679 * @interface_method_impl{VDIMAGEBACKEND,pfnSetOpenFlags}
680 */
681static DECLCALLBACK(int) visoSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
682{
683 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
684 LogFlowFunc(("pThis=%p fOpenFlags=%#x\n", pThis, uOpenFlags));
685
686 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
687 uint32_t const fSupported = VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
688 | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
689 | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS;
690 AssertMsgReturn(!(uOpenFlags & ~fSupported), ("fOpenFlags=%#x\n", uOpenFlags), VERR_INVALID_FLAGS);
691
692 /*
693 * Only react if we switch from VD_OPEN_FLAGS_INFO to non-VD_OPEN_FLAGS_INFO mode,
694 * becuase that means we need to open the image.
695 */
696 if ( (pThis->fOpenFlags & VD_OPEN_FLAGS_INFO)
697 && !(uOpenFlags & VD_OPEN_FLAGS_INFO)
698 && pThis->hIsoFile == NIL_RTVFSFILE)
699 {
700 int rc = visoOpenWorker(pThis);
701 if (RT_FAILURE(rc))
702 {
703 LogFlowFunc(("returns %Rrc\n", rc));
704 return rc;
705 }
706 }
707
708 /*
709 * Update the flags.
710 */
711 pThis->fOpenFlags &= ~fSupported;
712 pThis->fOpenFlags |= fSupported & uOpenFlags;
713 pThis->fOpenFlags |= VD_OPEN_FLAGS_READONLY;
714 if (pThis->hIsoFile != NIL_RTVFSFILE)
715 pThis->fOpenFlags &= ~VD_OPEN_FLAGS_INFO;
716
717 return VINF_SUCCESS;
718}
719
720#define uOpenFlags fOpenFlags /* sigh */
721
722/**
723 * @interface_method_impl{VDIMAGEBACKEND,pfnGetComment}
724 */
725VD_BACKEND_CALLBACK_GET_COMMENT_DEF_NOT_SUPPORTED(visoGetComment);
726
727/**
728 * @interface_method_impl{VDIMAGEBACKEND,pfnSetComment}
729 */
730VD_BACKEND_CALLBACK_SET_COMMENT_DEF_NOT_SUPPORTED(visoSetComment, PVISOIMAGE);
731
732/**
733 * @interface_method_impl{VDIMAGEBACKEND,pfnGetUuid}
734 */
735static DECLCALLBACK(int) visoGetUuid(void *pBackendData, PRTUUID pUuid)
736{
737 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
738 *pUuid = pThis->Uuid;
739 LogFlowFunc(("returns VIF_SUCCESS (%RTuuid)\n", pUuid));
740 return VINF_SUCCESS;
741}
742
743/**
744 * @interface_method_impl{VDIMAGEBACKEND,pfnSetUuid}
745 */
746VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetUuid, PVISOIMAGE);
747
748/**
749 * @interface_method_impl{VDIMAGEBACKEND,pfnGetModificationUuid}
750 */
751VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(visoGetModificationUuid);
752
753/**
754 * @interface_method_impl{VDIMAGEBACKEND,pfnSetModificationUuid}
755 */
756VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetModificationUuid, PVISOIMAGE);
757
758/**
759 * @interface_method_impl{VDIMAGEBACKEND,pfnGetParentUuid}
760 */
761VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(visoGetParentUuid);
762
763/**
764 * @interface_method_impl{VDIMAGEBACKEND,pfnSetParentUuid}
765 */
766VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetParentUuid, PVISOIMAGE);
767
768/**
769 * @interface_method_impl{VDIMAGEBACKEND,pfnGetParentModificationUuid}
770 */
771VD_BACKEND_CALLBACK_GET_UUID_DEF_NOT_SUPPORTED(visoGetParentModificationUuid);
772
773/**
774 * @interface_method_impl{VDIMAGEBACKEND,pfnSetParentModificationUuid}
775 */
776VD_BACKEND_CALLBACK_SET_UUID_DEF_NOT_SUPPORTED(visoSetParentModificationUuid, PVISOIMAGE);
777
778#undef uOpenFlags
779
780/**
781 * @interface_method_impl{VDIMAGEBACKEND,pfnDump}
782 */
783static DECLCALLBACK(void) visoDump(void *pBackendData)
784{
785 PVISOIMAGE pThis = (PVISOIMAGE)pBackendData;
786 AssertPtrReturnVoid(pThis);
787
788 vdIfErrorMessage(pThis->pIfError, "Dumping CUE image '%s' fOpenFlags=%x cbImage=%#RX64\n",
789 pThis->pszFilename, pThis->fOpenFlags, pThis->cbImage);
790}
791
792
793
794/**
795 * VBox ISO maker backend.
796 */
797const VDIMAGEBACKEND g_VBoxIsoMakerBackend =
798{
799 /* u32Version */
800 VD_IMGBACKEND_VERSION,
801 /* pszBackendName */
802 "VBoxIsoMaker",
803 /* uBackendCaps */
804 VD_CAP_FILE,
805 /* paFileExtensions */
806 g_aVBoXIsoMakerFileExtensions,
807 /* paConfigInfo */
808 NULL,
809 /* pfnProbe */
810 visoProbe,
811 /* pfnOpen */
812 visoOpen,
813 /* pfnCreate */
814 NULL,
815 /* pfnRename */
816 NULL,
817 /* pfnClose */
818 visoClose,
819 /* pfnRead */
820 visoRead,
821 /* pfnWrite */
822 visoWrite,
823 /* pfnFlush */
824 visoFlush,
825 /* pfnDiscard */
826 NULL,
827 /* pfnGetVersion */
828 visoGetVersion,
829 /* pfnGetFileSize */
830 visoGetFileSize,
831 /* pfnGetPCHSGeometry */
832 visoGetPCHSGeometry,
833 /* pfnSetPCHSGeometry */
834 visoSetPCHSGeometry,
835 /* pfnGetLCHSGeometry */
836 visoGetLCHSGeometry,
837 /* pfnSetLCHSGeometry */
838 visoSetLCHSGeometry,
839 /* pfnQueryRegions */
840 visoQueryRegions,
841 /* pfnRegionListRelease */
842 visoRegionListRelease,
843 /* pfnGetImageFlags */
844 visoGetImageFlags,
845 /* pfnGetOpenFlags */
846 visoGetOpenFlags,
847 /* pfnSetOpenFlags */
848 visoSetOpenFlags,
849 /* pfnGetComment */
850 visoGetComment,
851 /* pfnSetComment */
852 visoSetComment,
853 /* pfnGetUuid */
854 visoGetUuid,
855 /* pfnSetUuid */
856 visoSetUuid,
857 /* pfnGetModificationUuid */
858 visoGetModificationUuid,
859 /* pfnSetModificationUuid */
860 visoSetModificationUuid,
861 /* pfnGetParentUuid */
862 visoGetParentUuid,
863 /* pfnSetParentUuid */
864 visoSetParentUuid,
865 /* pfnGetParentModificationUuid */
866 visoGetParentModificationUuid,
867 /* pfnSetParentModificationUuid */
868 visoSetParentModificationUuid,
869 /* pfnDump */
870 visoDump,
871 /* pfnGetTimestamp */
872 NULL,
873 /* pfnGetParentTimestamp */
874 NULL,
875 /* pfnSetParentTimestamp */
876 NULL,
877 /* pfnGetParentFilename */
878 NULL,
879 /* pfnSetParentFilename */
880 NULL,
881 /* pfnComposeLocation */
882 genericFileComposeLocation,
883 /* pfnComposeName */
884 genericFileComposeName,
885 /* pfnCompact */
886 NULL,
887 /* pfnResize */
888 NULL,
889 /* pfnRepair */
890 NULL,
891 /* pfnTraverseMetadata */
892 NULL,
893 /* u32VersionEnd */
894 VD_IMGBACKEND_VERSION
895};
896
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