VirtualBox

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

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

IPRT/VISO: Pass a the directory of a VISO file to the ISO maker to allow for relative file/dir specification from it. Nested push-iso now possible. Tweak importer code to handle NT 3.1 iso where the big endian volume sequence number wasn't set.

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