VirtualBox

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

Last change on this file since 96206 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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