VirtualBox

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

Last change on this file since 97078 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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