VirtualBox

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

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

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

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