[21371] | 1 | /* $Id: Parallels.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | *
|
---|
| 4 | * Parallels hdd disk image, core code.
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | /*
|
---|
[98103] | 8 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[21371] | 9 | *
|
---|
[96407] | 10 | * This file is part of VirtualBox base platform packages, as
|
---|
| 11 | * available from https://www.virtualbox.org.
|
---|
| 12 | *
|
---|
| 13 | * This program is free software; you can redistribute it and/or
|
---|
| 14 | * modify it under the terms of the GNU General Public License
|
---|
| 15 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 16 | * License.
|
---|
| 17 | *
|
---|
| 18 | * This program is distributed in the hope that it will be useful, but
|
---|
| 19 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 21 | * General Public License for more details.
|
---|
| 22 | *
|
---|
| 23 | * You should have received a copy of the GNU General Public License
|
---|
| 24 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 25 | *
|
---|
| 26 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[21371] | 27 | */
|
---|
| 28 |
|
---|
[32536] | 29 | #define LOG_GROUP LOG_GROUP_VD_PARALLELS
|
---|
[33567] | 30 | #include <VBox/vd-plugin.h>
|
---|
[21371] | 31 | #include <VBox/err.h>
|
---|
| 32 |
|
---|
| 33 | #include <VBox/log.h>
|
---|
| 34 | #include <iprt/assert.h>
|
---|
[32536] | 35 | #include <iprt/mem.h>
|
---|
[21371] | 36 | #include <iprt/uuid.h>
|
---|
| 37 | #include <iprt/path.h>
|
---|
| 38 | #include <iprt/string.h>
|
---|
[40948] | 39 | #include <iprt/asm.h>
|
---|
[21371] | 40 |
|
---|
[50988] | 41 | #include "VDBackends.h"
|
---|
| 42 |
|
---|
[21371] | 43 | #define PARALLELS_HEADER_MAGIC "WithoutFreeSpace"
|
---|
| 44 | #define PARALLELS_DISK_VERSION 2
|
---|
| 45 |
|
---|
| 46 | /** The header of the parallels disk. */
|
---|
| 47 | #pragma pack(1)
|
---|
| 48 | typedef struct ParallelsHeader
|
---|
| 49 | {
|
---|
| 50 | /** The magic header to identify a parallels hdd image. */
|
---|
| 51 | char HeaderIdentifier[16];
|
---|
| 52 | /** The version of the disk image. */
|
---|
| 53 | uint32_t uVersion;
|
---|
| 54 | /** The number of heads the hdd has. */
|
---|
| 55 | uint32_t cHeads;
|
---|
| 56 | /** Number of cylinders. */
|
---|
| 57 | uint32_t cCylinders;
|
---|
| 58 | /** Number of sectors per track. */
|
---|
| 59 | uint32_t cSectorsPerTrack;
|
---|
| 60 | /** Number of entries in the allocation bitmap. */
|
---|
| 61 | uint32_t cEntriesInAllocationBitmap;
|
---|
| 62 | /** Total number of sectors. */
|
---|
| 63 | uint32_t cSectors;
|
---|
| 64 | /** Padding. */
|
---|
| 65 | char Padding[24];
|
---|
| 66 | } ParallelsHeader;
|
---|
| 67 | #pragma pack()
|
---|
| 68 |
|
---|
| 69 | /**
|
---|
| 70 | * Parallels image structure.
|
---|
| 71 | */
|
---|
| 72 | typedef struct PARALLELSIMAGE
|
---|
| 73 | {
|
---|
[32536] | 74 | /** Image file name. */
|
---|
| 75 | const char *pszFilename;
|
---|
| 76 | /** Opaque storage handle. */
|
---|
| 77 | PVDIOSTORAGE pStorage;
|
---|
| 78 |
|
---|
[21371] | 79 | /** Pointer to the per-disk VD interface list. */
|
---|
[28620] | 80 | PVDINTERFACE pVDIfsDisk;
|
---|
| 81 | /** Pointer to the per-image VD interface list. */
|
---|
| 82 | PVDINTERFACE pVDIfsImage;
|
---|
[21371] | 83 | /** Error interface. */
|
---|
[38469] | 84 | PVDINTERFACEERROR pIfError;
|
---|
| 85 | /** I/O interface. */
|
---|
| 86 | PVDINTERFACEIOINT pIfIo;
|
---|
[21371] | 87 |
|
---|
[32536] | 88 | /** Open flags passed by VBoxHDD layer. */
|
---|
[21371] | 89 | unsigned uOpenFlags;
|
---|
| 90 | /** Image flags defined during creation or determined during open. */
|
---|
| 91 | unsigned uImageFlags;
|
---|
| 92 | /** Total size of the image. */
|
---|
| 93 | uint64_t cbSize;
|
---|
[32536] | 94 |
|
---|
[21371] | 95 | /** Physical geometry of this image. */
|
---|
[32536] | 96 | VDGEOMETRY PCHSGeometry;
|
---|
[21371] | 97 | /** Logical geometry of this image. */
|
---|
[32536] | 98 | VDGEOMETRY LCHSGeometry;
|
---|
| 99 |
|
---|
[21371] | 100 | /** Pointer to the allocation bitmap. */
|
---|
| 101 | uint32_t *pAllocationBitmap;
|
---|
| 102 | /** Entries in the allocation bitmap. */
|
---|
| 103 | uint64_t cAllocationBitmapEntries;
|
---|
| 104 | /** Flag whether the allocation bitmap was changed. */
|
---|
| 105 | bool fAllocationBitmapChanged;
|
---|
| 106 | /** Current file size. */
|
---|
| 107 | uint64_t cbFileCurrent;
|
---|
[66486] | 108 | /** The static region list. */
|
---|
| 109 | VDREGIONLIST RegionList;
|
---|
[21371] | 110 | } PARALLELSIMAGE, *PPARALLELSIMAGE;
|
---|
| 111 |
|
---|
| 112 |
|
---|
[57358] | 113 | /*********************************************************************************************************************************
|
---|
| 114 | * Static Variables *
|
---|
| 115 | *********************************************************************************************************************************/
|
---|
| 116 |
|
---|
[21371] | 117 | /** NULL-terminated array of supported file extensions. */
|
---|
[33524] | 118 | static const VDFILEEXTENSION s_aParallelsFileExtensions[] =
|
---|
[21371] | 119 | {
|
---|
[33524] | 120 | {"hdd", VDTYPE_HDD},
|
---|
| 121 | {NULL, VDTYPE_INVALID}
|
---|
[21371] | 122 | };
|
---|
| 123 |
|
---|
| 124 | /***************************************************
|
---|
[57372] | 125 | * Internal functions *
|
---|
[21371] | 126 | **************************************************/
|
---|
| 127 |
|
---|
| 128 | /**
|
---|
[32536] | 129 | * Internal. Flush image data to disk.
|
---|
| 130 | */
|
---|
| 131 | static int parallelsFlushImage(PPARALLELSIMAGE pImage)
|
---|
[22966] | 132 | {
|
---|
| 133 | int rc = VINF_SUCCESS;
|
---|
| 134 |
|
---|
[32536] | 135 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 136 | return VINF_SUCCESS;
|
---|
[22966] | 137 |
|
---|
[32536] | 138 | if ( !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
|
---|
| 139 | && (pImage->fAllocationBitmapChanged))
|
---|
| 140 | {
|
---|
| 141 | pImage->fAllocationBitmapChanged = false;
|
---|
| 142 | /* Write the allocation bitmap to the file. */
|
---|
[38469] | 143 | rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
|
---|
| 144 | sizeof(ParallelsHeader), pImage->pAllocationBitmap,
|
---|
[44233] | 145 | pImage->cAllocationBitmapEntries * sizeof(uint32_t));
|
---|
[32536] | 146 | if (RT_FAILURE(rc))
|
---|
| 147 | return rc;
|
---|
| 148 | }
|
---|
| 149 |
|
---|
| 150 | /* Flush file. */
|
---|
[38469] | 151 | rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);
|
---|
[32536] | 152 |
|
---|
| 153 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
[22966] | 154 | return rc;
|
---|
| 155 | }
|
---|
| 156 |
|
---|
[32536] | 157 | /**
|
---|
| 158 | * Internal. Free all allocated space for representing an image except pImage,
|
---|
| 159 | * and optionally delete the image from disk.
|
---|
| 160 | */
|
---|
| 161 | static int parallelsFreeImage(PPARALLELSIMAGE pImage, bool fDelete)
|
---|
[22966] | 162 | {
|
---|
| 163 | int rc = VINF_SUCCESS;
|
---|
| 164 |
|
---|
[32536] | 165 | /* Freeing a never allocated image (e.g. because the open failed) is
|
---|
| 166 | * not signalled as an error. After all nothing bad happens. */
|
---|
| 167 | if (pImage)
|
---|
| 168 | {
|
---|
| 169 | if (pImage->pStorage)
|
---|
| 170 | {
|
---|
| 171 | /* No point updating the file that is deleted anyway. */
|
---|
| 172 | if (!fDelete)
|
---|
| 173 | parallelsFlushImage(pImage);
|
---|
[22966] | 174 |
|
---|
[46613] | 175 | rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
|
---|
[32536] | 176 | pImage->pStorage = NULL;
|
---|
| 177 | }
|
---|
| 178 |
|
---|
| 179 | if (pImage->pAllocationBitmap)
|
---|
| 180 | {
|
---|
| 181 | RTMemFree(pImage->pAllocationBitmap);
|
---|
| 182 | pImage->pAllocationBitmap = NULL;
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | if (fDelete && pImage->pszFilename)
|
---|
[38469] | 186 | vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
|
---|
[32536] | 187 | }
|
---|
| 188 |
|
---|
[22966] | 189 | return rc;
|
---|
| 190 | }
|
---|
| 191 |
|
---|
[21371] | 192 | static int parallelsOpenImage(PPARALLELSIMAGE pImage, unsigned uOpenFlags)
|
---|
| 193 | {
|
---|
[38469] | 194 | pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
|
---|
| 195 | pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
|
---|
[46170] | 196 | pImage->uOpenFlags = uOpenFlags;
|
---|
[38469] | 197 | AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
|
---|
[21371] | 198 |
|
---|
[63780] | 199 | int rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename,
|
---|
| 200 | VDOpenFlagsToFileOpenFlags(uOpenFlags,
|
---|
| 201 | false /* fCreate */),
|
---|
| 202 | &pImage->pStorage);
|
---|
| 203 | if (RT_SUCCESS(rc))
|
---|
[63635] | 204 | {
|
---|
[63780] | 205 | rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &pImage->cbFileCurrent);
|
---|
| 206 | if (RT_SUCCESS(rc)
|
---|
| 207 | && !(pImage->cbFileCurrent % 512))
|
---|
[21371] | 208 | {
|
---|
[63780] | 209 | ParallelsHeader parallelsHeader;
|
---|
[21371] | 210 |
|
---|
[63780] | 211 | rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0,
|
---|
| 212 | ¶llelsHeader, sizeof(parallelsHeader));
|
---|
| 213 | if (RT_SUCCESS(rc))
|
---|
| 214 | {
|
---|
| 215 | if (memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16))
|
---|
| 216 | {
|
---|
| 217 | /* Check if the file has hdd as extension. It is a fixed size raw image then. */
|
---|
| 218 | char *pszSuffix = RTPathSuffix(pImage->pszFilename);
|
---|
| 219 | if (!strcmp(pszSuffix, ".hdd"))
|
---|
| 220 | {
|
---|
| 221 | /* This is a fixed size image. */
|
---|
| 222 | pImage->uImageFlags |= VD_IMAGE_FLAGS_FIXED;
|
---|
| 223 | pImage->cbSize = pImage->cbFileCurrent;
|
---|
[21371] | 224 |
|
---|
[63780] | 225 | pImage->PCHSGeometry.cHeads = 16;
|
---|
| 226 | pImage->PCHSGeometry.cSectors = 63;
|
---|
| 227 | uint64_t cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
|
---|
| 228 | pImage->PCHSGeometry.cCylinders = (uint32_t)cCylinders;
|
---|
| 229 | }
|
---|
| 230 | else
|
---|
| 231 | rc = VERR_VD_PARALLELS_INVALID_HEADER;
|
---|
| 232 | }
|
---|
| 233 | else
|
---|
| 234 | {
|
---|
| 235 | if ( parallelsHeader.uVersion == PARALLELS_DISK_VERSION
|
---|
| 236 | && parallelsHeader.cEntriesInAllocationBitmap <= (1 << 30))
|
---|
| 237 | {
|
---|
| 238 | Log(("cSectors=%u\n", parallelsHeader.cSectors));
|
---|
| 239 | pImage->cbSize = ((uint64_t)parallelsHeader.cSectors) * 512;
|
---|
| 240 | pImage->uImageFlags = VD_IMAGE_FLAGS_NONE;
|
---|
| 241 | pImage->PCHSGeometry.cCylinders = parallelsHeader.cCylinders;
|
---|
| 242 | pImage->PCHSGeometry.cHeads = parallelsHeader.cHeads;
|
---|
| 243 | pImage->PCHSGeometry.cSectors = parallelsHeader.cSectorsPerTrack;
|
---|
| 244 | pImage->cAllocationBitmapEntries = parallelsHeader.cEntriesInAllocationBitmap;
|
---|
| 245 | pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ((uint32_t)pImage->cAllocationBitmapEntries * sizeof(uint32_t));
|
---|
| 246 | if (RT_LIKELY(pImage->pAllocationBitmap))
|
---|
| 247 | rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
|
---|
| 248 | sizeof(ParallelsHeader), pImage->pAllocationBitmap,
|
---|
| 249 | pImage->cAllocationBitmapEntries * sizeof(uint32_t));
|
---|
| 250 | else
|
---|
| 251 | rc = VERR_NO_MEMORY;
|
---|
| 252 | }
|
---|
| 253 | else
|
---|
| 254 | rc = VERR_NOT_SUPPORTED;
|
---|
| 255 | }
|
---|
| 256 | }
|
---|
[21371] | 257 | }
|
---|
[63780] | 258 | else if (RT_SUCCESS(rc))
|
---|
| 259 | rc = VERR_VD_PARALLELS_INVALID_HEADER;
|
---|
[21371] | 260 | }
|
---|
| 261 |
|
---|
[66486] | 262 | if (RT_SUCCESS(rc))
|
---|
| 263 | {
|
---|
| 264 | PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
|
---|
| 265 | pImage->RegionList.fFlags = 0;
|
---|
| 266 | pImage->RegionList.cRegions = 1;
|
---|
| 267 |
|
---|
| 268 | pRegion->offRegion = 0; /* Disk start. */
|
---|
| 269 | pRegion->cbBlock = 512;
|
---|
| 270 | pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
|
---|
| 271 | pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
|
---|
| 272 | pRegion->cbData = 512;
|
---|
| 273 | pRegion->cbMetadata = 0;
|
---|
| 274 | pRegion->cRegionBlocksOrBytes = pImage->cbSize;
|
---|
| 275 | }
|
---|
[77699] | 276 | else
|
---|
| 277 | parallelsFreeImage(pImage, false);
|
---|
[66486] | 278 |
|
---|
[21371] | 279 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 280 | return rc;
|
---|
| 281 | }
|
---|
| 282 |
|
---|
[38413] | 283 | /**
|
---|
| 284 | * Internal: Create a parallels image.
|
---|
| 285 | */
|
---|
| 286 | static int parallelsCreateImage(PPARALLELSIMAGE pImage, uint64_t cbSize,
|
---|
| 287 | unsigned uImageFlags, const char *pszComment,
|
---|
| 288 | PCVDGEOMETRY pPCHSGeometry,
|
---|
| 289 | PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
|
---|
| 290 | PFNVDPROGRESS pfnProgress, void *pvUser,
|
---|
| 291 | unsigned uPercentStart, unsigned uPercentSpan)
|
---|
| 292 | {
|
---|
[62751] | 293 | RT_NOREF1(pszComment);
|
---|
[38413] | 294 | int rc = VINF_SUCCESS;
|
---|
| 295 | int32_t fOpen;
|
---|
[21371] | 296 |
|
---|
[63780] | 297 | if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
|
---|
[38413] | 298 | {
|
---|
[63780] | 299 | pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
|
---|
| 300 | pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
|
---|
| 301 | AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);
|
---|
[38413] | 302 |
|
---|
[63780] | 303 | pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
|
---|
| 304 | pImage->uImageFlags = uImageFlags;
|
---|
| 305 | pImage->PCHSGeometry = *pPCHSGeometry;
|
---|
| 306 | pImage->LCHSGeometry = *pLCHSGeometry;
|
---|
| 307 | if (!pImage->PCHSGeometry.cCylinders)
|
---|
| 308 | {
|
---|
| 309 | /* Set defaults. */
|
---|
| 310 | pImage->PCHSGeometry.cSectors = 63;
|
---|
| 311 | pImage->PCHSGeometry.cHeads = 16;
|
---|
| 312 | pImage->PCHSGeometry.cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
|
---|
| 313 | }
|
---|
[38413] | 314 |
|
---|
[63780] | 315 | /* Create image file. */
|
---|
| 316 | fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
|
---|
| 317 | rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
|
---|
| 318 | if (RT_SUCCESS(rc))
|
---|
| 319 | {
|
---|
| 320 | if (pfnProgress)
|
---|
| 321 | pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);
|
---|
[38413] | 322 |
|
---|
[63780] | 323 | /* Setup image state. */
|
---|
| 324 | pImage->cbSize = cbSize;
|
---|
| 325 | pImage->cAllocationBitmapEntries = cbSize / 512 / pImage->PCHSGeometry.cSectors;
|
---|
| 326 | if (pImage->cAllocationBitmapEntries * pImage->PCHSGeometry.cSectors * 512 < cbSize)
|
---|
| 327 | pImage->cAllocationBitmapEntries++;
|
---|
| 328 | pImage->fAllocationBitmapChanged = true;
|
---|
| 329 | pImage->cbFileCurrent = sizeof(ParallelsHeader) + pImage->cAllocationBitmapEntries * sizeof(uint32_t);
|
---|
| 330 | /* Round to next sector boundary. */
|
---|
| 331 | pImage->cbFileCurrent += 512 - pImage->cbFileCurrent % 512;
|
---|
| 332 | Assert(!(pImage->cbFileCurrent % 512));
|
---|
| 333 | pImage->pAllocationBitmap = (uint32_t *)RTMemAllocZ(pImage->cAllocationBitmapEntries * sizeof(uint32_t));
|
---|
| 334 | if (pImage->pAllocationBitmap)
|
---|
| 335 | {
|
---|
| 336 | ParallelsHeader Header;
|
---|
[38413] | 337 |
|
---|
[63780] | 338 | memcpy(Header.HeaderIdentifier, PARALLELS_HEADER_MAGIC, sizeof(Header.HeaderIdentifier));
|
---|
| 339 | Header.uVersion = RT_H2LE_U32(PARALLELS_DISK_VERSION);
|
---|
| 340 | Header.cHeads = RT_H2LE_U32(pImage->PCHSGeometry.cHeads);
|
---|
| 341 | Header.cCylinders = RT_H2LE_U32(pImage->PCHSGeometry.cCylinders);
|
---|
| 342 | Header.cSectorsPerTrack = RT_H2LE_U32(pImage->PCHSGeometry.cSectors);
|
---|
| 343 | Header.cEntriesInAllocationBitmap = RT_H2LE_U32(pImage->cAllocationBitmapEntries);
|
---|
| 344 | Header.cSectors = RT_H2LE_U32(pImage->cbSize / 512);
|
---|
| 345 | memset(Header.Padding, 0, sizeof(Header.Padding));
|
---|
[38413] | 346 |
|
---|
[63780] | 347 | /* Write header and allocation bitmap. */
|
---|
| 348 | rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbFileCurrent);
|
---|
| 349 | if (RT_SUCCESS(rc))
|
---|
| 350 | rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0,
|
---|
| 351 | &Header, sizeof(Header));
|
---|
| 352 | if (RT_SUCCESS(rc))
|
---|
| 353 | rc = parallelsFlushImage(pImage); /* Writes the allocation bitmap. */
|
---|
| 354 | }
|
---|
| 355 | else
|
---|
| 356 | rc = VERR_NO_MEMORY;
|
---|
| 357 | }
|
---|
| 358 | else
|
---|
| 359 | rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Parallels: cannot create image '%s'"), pImage->pszFilename);
|
---|
[38413] | 360 | }
|
---|
[63780] | 361 | else
|
---|
| 362 | rc = vdIfError(pImage->pIfError, VERR_VD_INVALID_TYPE, RT_SRC_POS, N_("Parallels: cannot create fixed image '%s'. Create a raw image"), pImage->pszFilename);
|
---|
[38413] | 363 |
|
---|
| 364 | if (RT_SUCCESS(rc) && pfnProgress)
|
---|
| 365 | pfnProgress(pvUser, uPercentStart + uPercentSpan);
|
---|
| 366 |
|
---|
[66486] | 367 | if (RT_SUCCESS(rc))
|
---|
| 368 | {
|
---|
| 369 | PVDREGIONDESC pRegion = &pImage->RegionList.aRegions[0];
|
---|
| 370 | pImage->RegionList.fFlags = 0;
|
---|
| 371 | pImage->RegionList.cRegions = 1;
|
---|
| 372 |
|
---|
| 373 | pRegion->offRegion = 0; /* Disk start. */
|
---|
| 374 | pRegion->cbBlock = 512;
|
---|
| 375 | pRegion->enmDataForm = VDREGIONDATAFORM_RAW;
|
---|
| 376 | pRegion->enmMetadataForm = VDREGIONMETADATAFORM_NONE;
|
---|
| 377 | pRegion->cbData = 512;
|
---|
| 378 | pRegion->cbMetadata = 0;
|
---|
| 379 | pRegion->cRegionBlocksOrBytes = pImage->cbSize;
|
---|
| 380 | }
|
---|
| 381 | else
|
---|
[38413] | 382 | parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
|
---|
| 383 | return rc;
|
---|
| 384 | }
|
---|
| 385 |
|
---|
[64277] | 386 | /** @copydoc VDIMAGEBACKEND::pfnProbe */
|
---|
[63802] | 387 | static DECLCALLBACK(int) parallelsProbe(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
|
---|
[79965] | 388 | PVDINTERFACE pVDIfsImage, VDTYPE enmDesiredType, VDTYPE *penmType)
|
---|
[21371] | 389 | {
|
---|
[79965] | 390 | RT_NOREF(pVDIfsDisk, enmDesiredType);
|
---|
[32536] | 391 | int rc;
|
---|
| 392 | PVDIOSTORAGE pStorage;
|
---|
[21371] | 393 | ParallelsHeader parallelsHeader;
|
---|
| 394 |
|
---|
[38469] | 395 | PVDINTERFACEIOINT pIfIo = VDIfIoIntGet(pVDIfsImage);
|
---|
| 396 | AssertPtrReturn(pIfIo, VERR_INVALID_PARAMETER);
|
---|
[32536] | 397 |
|
---|
[38469] | 398 | rc = vdIfIoIntFileOpen(pIfIo, pszFilename,
|
---|
| 399 | VDOpenFlagsToFileOpenFlags(VD_OPEN_FLAGS_READONLY,
|
---|
| 400 | false /* fCreate */),
|
---|
| 401 | &pStorage);
|
---|
[21371] | 402 | if (RT_FAILURE(rc))
|
---|
[32536] | 403 | return rc;
|
---|
[21371] | 404 |
|
---|
[38469] | 405 | rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, ¶llelsHeader,
|
---|
[44233] | 406 | sizeof(ParallelsHeader));
|
---|
[32536] | 407 | if (RT_SUCCESS(rc))
|
---|
[21371] | 408 | {
|
---|
| 409 | if ( !memcmp(parallelsHeader.HeaderIdentifier, PARALLELS_HEADER_MAGIC, 16)
|
---|
| 410 | && (parallelsHeader.uVersion == PARALLELS_DISK_VERSION))
|
---|
| 411 | rc = VINF_SUCCESS;
|
---|
| 412 | else
|
---|
| 413 | {
|
---|
| 414 | /*
|
---|
| 415 | * The image may be an fixed size image.
|
---|
| 416 | * Unfortunately fixed sized parallels images
|
---|
| 417 | * are just raw files hence no magic header to
|
---|
| 418 | * check for.
|
---|
| 419 | * The code succeeds if the file is a multiple
|
---|
| 420 | * of 512 and if the file extensions is *.hdd
|
---|
| 421 | */
|
---|
| 422 | uint64_t cbFile;
|
---|
[49039] | 423 | char *pszSuffix;
|
---|
[21371] | 424 |
|
---|
[38469] | 425 | rc = vdIfIoIntFileGetSize(pIfIo, pStorage, &cbFile);
|
---|
[21371] | 426 | if (RT_FAILURE(rc) || ((cbFile % 512) != 0))
|
---|
| 427 | {
|
---|
[38469] | 428 | vdIfIoIntFileClose(pIfIo, pStorage);
|
---|
[32536] | 429 | return VERR_VD_PARALLELS_INVALID_HEADER;
|
---|
[21371] | 430 | }
|
---|
| 431 |
|
---|
[49039] | 432 | pszSuffix = RTPathSuffix(pszFilename);
|
---|
| 433 | if (!pszSuffix || strcmp(pszSuffix, ".hdd"))
|
---|
[32536] | 434 | rc = VERR_VD_PARALLELS_INVALID_HEADER;
|
---|
[21371] | 435 | else
|
---|
| 436 | rc = VINF_SUCCESS;
|
---|
| 437 | }
|
---|
| 438 | }
|
---|
| 439 |
|
---|
[33524] | 440 | if (RT_SUCCESS(rc))
|
---|
| 441 | *penmType = VDTYPE_HDD;
|
---|
| 442 |
|
---|
[38469] | 443 | vdIfIoIntFileClose(pIfIo, pStorage);
|
---|
[21371] | 444 | return rc;
|
---|
| 445 | }
|
---|
| 446 |
|
---|
[63783] | 447 | /** @copydoc VDIMAGEBACKEND::pfnOpen */
|
---|
[57388] | 448 | static DECLCALLBACK(int) parallelsOpen(const char *pszFilename, unsigned uOpenFlags,
|
---|
| 449 | PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
|
---|
| 450 | VDTYPE enmType, void **ppBackendData)
|
---|
[21371] | 451 | {
|
---|
[54430] | 452 | LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
|
---|
[21371] | 453 | int rc;
|
---|
| 454 | PPARALLELSIMAGE pImage;
|
---|
| 455 |
|
---|
[54430] | 456 | NOREF(enmType); /**< @todo r=klaus make use of the type info. */
|
---|
| 457 |
|
---|
[63780] | 458 | /* Check parameters. */
|
---|
| 459 | AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
|
---|
[90802] | 460 | AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
|
---|
| 461 | AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
|
---|
[21371] | 462 |
|
---|
[90802] | 463 |
|
---|
[66486] | 464 | pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
|
---|
[63780] | 465 | if (RT_LIKELY(pImage))
|
---|
[21371] | 466 | {
|
---|
[63780] | 467 | pImage->pszFilename = pszFilename;
|
---|
| 468 | pImage->pStorage = NULL;
|
---|
| 469 | pImage->pVDIfsDisk = pVDIfsDisk;
|
---|
| 470 | pImage->pVDIfsImage = pVDIfsImage;
|
---|
| 471 | pImage->fAllocationBitmapChanged = false;
|
---|
[21371] | 472 |
|
---|
[63780] | 473 | rc = parallelsOpenImage(pImage, uOpenFlags);
|
---|
| 474 | if (RT_SUCCESS(rc))
|
---|
| 475 | *ppBackendData = pImage;
|
---|
| 476 | else
|
---|
| 477 | RTMemFree(pImage);
|
---|
[21371] | 478 | }
|
---|
[32536] | 479 | else
|
---|
[63780] | 480 | rc = VERR_NO_MEMORY;
|
---|
[21371] | 481 |
|
---|
| 482 | LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
|
---|
| 483 | return rc;
|
---|
| 484 | }
|
---|
| 485 |
|
---|
[63783] | 486 | /** @copydoc VDIMAGEBACKEND::pfnCreate */
|
---|
[57388] | 487 | static DECLCALLBACK(int) parallelsCreate(const char *pszFilename, uint64_t cbSize,
|
---|
| 488 | unsigned uImageFlags, const char *pszComment,
|
---|
| 489 | PCVDGEOMETRY pPCHSGeometry,
|
---|
| 490 | PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
|
---|
| 491 | unsigned uOpenFlags, unsigned uPercentStart,
|
---|
| 492 | unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
|
---|
| 493 | PVDINTERFACE pVDIfsImage,
|
---|
| 494 | PVDINTERFACE pVDIfsOperation, VDTYPE enmType,
|
---|
| 495 | void **ppBackendData)
|
---|
[21371] | 496 | {
|
---|
[62751] | 497 | RT_NOREF1(pUuid);
|
---|
[54430] | 498 | LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p enmType=%u ppBackendData=%#p",
|
---|
| 499 | pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
|
---|
[63780] | 500 |
|
---|
| 501 | /* Check the VD container type. */
|
---|
| 502 | if (enmType != VDTYPE_HDD)
|
---|
| 503 | return VERR_VD_INVALID_TYPE;
|
---|
| 504 |
|
---|
| 505 | /* Check arguments. */
|
---|
| 506 | AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
|
---|
[90802] | 507 | AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
|
---|
| 508 | AssertReturn(*pszFilename != '\0', VERR_INVALID_PARAMETER);
|
---|
| 509 | AssertPtrReturn(pPCHSGeometry, VERR_INVALID_POINTER);
|
---|
| 510 | AssertPtrReturn(pLCHSGeometry, VERR_INVALID_POINTER);
|
---|
[63780] | 511 |
|
---|
[38413] | 512 | int rc = VINF_SUCCESS;
|
---|
| 513 | PPARALLELSIMAGE pImage;
|
---|
| 514 | PFNVDPROGRESS pfnProgress = NULL;
|
---|
| 515 | void *pvUser = NULL;
|
---|
[38469] | 516 | PVDINTERFACEPROGRESS pIfProgress = VDIfProgressGet(pVDIfsOperation);
|
---|
[38413] | 517 | if (pIfProgress)
|
---|
| 518 | {
|
---|
[38469] | 519 | pfnProgress = pIfProgress->pfnProgress;
|
---|
| 520 | pvUser = pIfProgress->Core.pvUser;
|
---|
[38413] | 521 | }
|
---|
| 522 |
|
---|
[66486] | 523 | pImage = (PPARALLELSIMAGE)RTMemAllocZ(RT_UOFFSETOF(PARALLELSIMAGE, RegionList.aRegions[1]));
|
---|
[63780] | 524 | if (RT_LIKELY(pImage))
|
---|
[38413] | 525 | {
|
---|
[63780] | 526 | pImage->pszFilename = pszFilename;
|
---|
| 527 | pImage->pStorage = NULL;
|
---|
| 528 | pImage->pVDIfsDisk = pVDIfsDisk;
|
---|
| 529 | pImage->pVDIfsImage = pVDIfsImage;
|
---|
[38413] | 530 |
|
---|
[63780] | 531 | rc = parallelsCreateImage(pImage, cbSize, uImageFlags, pszComment,
|
---|
| 532 | pPCHSGeometry, pLCHSGeometry, uOpenFlags,
|
---|
| 533 | pfnProgress, pvUser, uPercentStart, uPercentSpan);
|
---|
| 534 | if (RT_SUCCESS(rc))
|
---|
[38413] | 535 | {
|
---|
[63780] | 536 | /* So far the image is opened in read/write mode. Make sure the
|
---|
| 537 | * image is opened in read-only mode if the caller requested that. */
|
---|
| 538 | if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
[38413] | 539 | {
|
---|
[63780] | 540 | parallelsFreeImage(pImage, false);
|
---|
| 541 | rc = parallelsOpenImage(pImage, uOpenFlags);
|
---|
[38413] | 542 | }
|
---|
[63780] | 543 |
|
---|
| 544 | if (RT_SUCCESS(rc))
|
---|
| 545 | *ppBackendData = pImage;
|
---|
[38413] | 546 | }
|
---|
[63780] | 547 |
|
---|
| 548 | if (RT_FAILURE(rc))
|
---|
| 549 | RTMemFree(pImage);
|
---|
[38413] | 550 | }
|
---|
| 551 | else
|
---|
[63780] | 552 | rc = VERR_NO_MEMORY;
|
---|
[38413] | 553 |
|
---|
[32536] | 554 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 555 | return rc;
|
---|
[21371] | 556 | }
|
---|
| 557 |
|
---|
[63783] | 558 | /** @copydoc VDIMAGEBACKEND::pfnRename */
|
---|
[57388] | 559 | static DECLCALLBACK(int) parallelsRename(void *pBackendData, const char *pszFilename)
|
---|
[21371] | 560 | {
|
---|
| 561 | LogFlowFunc(("pBackendData=%#p pszFilename=%#p\n", pBackendData, pszFilename));
|
---|
[32536] | 562 | int rc = VINF_SUCCESS;
|
---|
| 563 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 564 |
|
---|
| 565 | /* Check arguments. */
|
---|
[63780] | 566 | AssertReturn((pImage && pszFilename && *pszFilename), VERR_INVALID_PARAMETER);
|
---|
[32536] | 567 |
|
---|
| 568 | /* Close the image. */
|
---|
| 569 | rc = parallelsFreeImage(pImage, false);
|
---|
[63780] | 570 | if (RT_SUCCESS(rc))
|
---|
[32536] | 571 | {
|
---|
[63780] | 572 | /* Rename the file. */
|
---|
| 573 | rc = vdIfIoIntFileMove(pImage->pIfIo, pImage->pszFilename, pszFilename, 0);
|
---|
| 574 | if (RT_SUCCESS(rc))
|
---|
| 575 | {
|
---|
| 576 | /* Update pImage with the new information. */
|
---|
| 577 | pImage->pszFilename = pszFilename;
|
---|
[32536] | 578 |
|
---|
[63780] | 579 | /* Open the old image with new name. */
|
---|
| 580 | rc = parallelsOpenImage(pImage, pImage->uOpenFlags);
|
---|
| 581 | }
|
---|
| 582 | else
|
---|
| 583 | {
|
---|
| 584 | /* The move failed, try to reopen the original image. */
|
---|
| 585 | int rc2 = parallelsOpenImage(pImage, pImage->uOpenFlags);
|
---|
| 586 | if (RT_FAILURE(rc2))
|
---|
| 587 | rc = rc2;
|
---|
| 588 | }
|
---|
[32536] | 589 | }
|
---|
| 590 |
|
---|
| 591 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 592 | return rc;
|
---|
[21371] | 593 | }
|
---|
| 594 |
|
---|
[63783] | 595 | /** @copydoc VDIMAGEBACKEND::pfnClose */
|
---|
[57388] | 596 | static DECLCALLBACK(int) parallelsClose(void *pBackendData, bool fDelete)
|
---|
[21371] | 597 | {
|
---|
| 598 | LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
|
---|
| 599 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[63780] | 600 | int rc = parallelsFreeImage(pImage, fDelete);
|
---|
[32536] | 601 | RTMemFree(pImage);
|
---|
[21371] | 602 |
|
---|
| 603 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 604 | return rc;
|
---|
| 605 | }
|
---|
| 606 |
|
---|
[63783] | 607 | /** @copydoc VDIMAGEBACKEND::pfnRead */
|
---|
[57388] | 608 | static DECLCALLBACK(int) parallelsRead(void *pBackendData, uint64_t uOffset, size_t cbToRead,
|
---|
| 609 | PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
|
---|
[21371] | 610 | {
|
---|
[44252] | 611 | LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
|
---|
| 612 | pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
|
---|
| 613 | int rc = VINF_SUCCESS;
|
---|
[32536] | 614 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[44252] | 615 | uint64_t uSector;
|
---|
| 616 | uint64_t uOffsetInFile;
|
---|
| 617 | uint32_t iIndexInAllocationTable;
|
---|
[21371] | 618 |
|
---|
[32536] | 619 | AssertPtr(pImage);
|
---|
[21371] | 620 | Assert(uOffset % 512 == 0);
|
---|
[38413] | 621 | Assert(cbToRead % 512 == 0);
|
---|
[21371] | 622 |
|
---|
| 623 | if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
|
---|
[44252] | 624 | rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset,
|
---|
| 625 | pIoCtx, cbToRead);
|
---|
[21371] | 626 | else
|
---|
| 627 | {
|
---|
[30863] | 628 | /* Calculate offset in the real file. */
|
---|
[21371] | 629 | uSector = uOffset / 512;
|
---|
[30863] | 630 | /* One chunk in the file is always one track big. */
|
---|
[21371] | 631 | iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
|
---|
| 632 | uSector = uSector % pImage->PCHSGeometry.cSectors;
|
---|
| 633 |
|
---|
[38413] | 634 | cbToRead = RT_MIN(cbToRead, (pImage->PCHSGeometry.cSectors - uSector)*512);
|
---|
| 635 |
|
---|
[21371] | 636 | if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
|
---|
| 637 | rc = VERR_VD_BLOCK_FREE;
|
---|
| 638 | else
|
---|
| 639 | {
|
---|
[44252] | 640 | uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
|
---|
| 641 | rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
|
---|
| 642 | pIoCtx, cbToRead);
|
---|
[21371] | 643 | }
|
---|
| 644 | }
|
---|
| 645 |
|
---|
[44252] | 646 | *pcbActuallyRead = cbToRead;
|
---|
[21371] | 647 |
|
---|
| 648 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 649 | return rc;
|
---|
| 650 | }
|
---|
| 651 |
|
---|
[63783] | 652 | /** @copydoc VDIMAGEBACKEND::pfnWrite */
|
---|
[57388] | 653 | static DECLCALLBACK(int) parallelsWrite(void *pBackendData, uint64_t uOffset, size_t cbToWrite,
|
---|
| 654 | PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
|
---|
| 655 | size_t *pcbPostRead, unsigned fWrite)
|
---|
[21371] | 656 | {
|
---|
[44252] | 657 | LogFlowFunc(("pBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
|
---|
| 658 | pBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess));
|
---|
| 659 | int rc = VINF_SUCCESS;
|
---|
[32536] | 660 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[44252] | 661 | uint64_t uSector;
|
---|
| 662 | uint64_t uOffsetInFile;
|
---|
| 663 | uint32_t iIndexInAllocationTable;
|
---|
[21371] | 664 |
|
---|
[32536] | 665 | AssertPtr(pImage);
|
---|
[21371] | 666 | Assert(uOffset % 512 == 0);
|
---|
[38413] | 667 | Assert(cbToWrite % 512 == 0);
|
---|
[21371] | 668 |
|
---|
| 669 | if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
|
---|
[44252] | 670 | rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage, uOffset,
|
---|
| 671 | pIoCtx, cbToWrite, NULL, NULL);
|
---|
[21371] | 672 | else
|
---|
| 673 | {
|
---|
[38413] | 674 | /* Calculate offset in the real file. */
|
---|
[21371] | 675 | uSector = uOffset / 512;
|
---|
[38413] | 676 | /* One chunk in the file is always one track big. */
|
---|
[21371] | 677 | iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
|
---|
| 678 | uSector = uSector % pImage->PCHSGeometry.cSectors;
|
---|
| 679 |
|
---|
[38413] | 680 | cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);
|
---|
| 681 |
|
---|
[21371] | 682 | if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
|
---|
| 683 | {
|
---|
[44252] | 684 | if (fWrite & VD_WRITE_NO_ALLOC)
|
---|
[38413] | 685 | {
|
---|
[44252] | 686 | *pcbPreRead = uSector * 512;
|
---|
| 687 | *pcbPostRead = pImage->PCHSGeometry.cSectors * 512 - cbToWrite - *pcbPreRead;
|
---|
[22966] | 688 |
|
---|
[44252] | 689 | if (pcbWriteProcess)
|
---|
| 690 | *pcbWriteProcess = cbToWrite;
|
---|
| 691 | return VERR_VD_BLOCK_FREE;
|
---|
| 692 | }
|
---|
[22966] | 693 |
|
---|
[44252] | 694 | /* Allocate new chunk in the file. */
|
---|
| 695 | Assert(uSector == 0);
|
---|
| 696 | AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
|
---|
| 697 | pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
|
---|
| 698 | pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
|
---|
| 699 | pImage->fAllocationBitmapChanged = true;
|
---|
| 700 | uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;
|
---|
[38413] | 701 |
|
---|
[44252] | 702 | /*
|
---|
| 703 | * Write the new block at the current end of the file.
|
---|
| 704 | */
|
---|
| 705 | rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
|
---|
| 706 | uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
|
---|
| 707 | if (RT_SUCCESS(rc) || (rc == VERR_VD_ASYNC_IO_IN_PROGRESS))
|
---|
[32536] | 708 | {
|
---|
[44252] | 709 | /* Write the changed allocation bitmap entry. */
|
---|
[63567] | 710 | /** @todo Error handling. */
|
---|
[44252] | 711 | rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
|
---|
| 712 | sizeof(ParallelsHeader) + iIndexInAllocationTable * sizeof(uint32_t),
|
---|
| 713 | &pImage->pAllocationBitmap[iIndexInAllocationTable],
|
---|
| 714 | sizeof(uint32_t), pIoCtx,
|
---|
| 715 | NULL, NULL);
|
---|
[32536] | 716 | }
|
---|
[44252] | 717 |
|
---|
| 718 | *pcbPreRead = 0;
|
---|
| 719 | *pcbPostRead = 0;
|
---|
[21371] | 720 | }
|
---|
[22966] | 721 | else
|
---|
| 722 | {
|
---|
[44252] | 723 | uOffsetInFile = (pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;
|
---|
| 724 | rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
|
---|
| 725 | uOffsetInFile, pIoCtx, cbToWrite, NULL, NULL);
|
---|
[22966] | 726 | }
|
---|
[21371] | 727 | }
|
---|
| 728 |
|
---|
[32536] | 729 | if (pcbWriteProcess)
|
---|
[38413] | 730 | *pcbWriteProcess = cbToWrite;
|
---|
[21371] | 731 |
|
---|
| 732 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 733 | return rc;
|
---|
| 734 | }
|
---|
| 735 |
|
---|
[63783] | 736 | /** @copydoc VDIMAGEBACKEND::pfnFlush */
|
---|
[57388] | 737 | static DECLCALLBACK(int) parallelsFlush(void *pBackendData, PVDIOCTX pIoCtx)
|
---|
[21371] | 738 | {
|
---|
[44252] | 739 | int rc = VINF_SUCCESS;
|
---|
[21371] | 740 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 741 |
|
---|
[44252] | 742 | LogFlowFunc(("pImage=#%p\n", pImage));
|
---|
[21371] | 743 |
|
---|
[44252] | 744 | /* Flush the file, everything is up to date already. */
|
---|
| 745 | rc = vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
|
---|
[21371] | 746 |
|
---|
| 747 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 748 | return rc;
|
---|
| 749 | }
|
---|
| 750 |
|
---|
[63783] | 751 | /** @copydoc VDIMAGEBACKEND::pfnGetVersion */
|
---|
[57388] | 752 | static DECLCALLBACK(unsigned) parallelsGetVersion(void *pBackendData)
|
---|
[21371] | 753 | {
|
---|
| 754 | LogFlowFunc(("pBackendData=%#p\n", pBackendData));
|
---|
| 755 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 756 |
|
---|
[63780] | 757 | AssertPtrReturn(pImage, 0);
|
---|
[21371] | 758 |
|
---|
[63780] | 759 | return PARALLELS_DISK_VERSION;
|
---|
[21371] | 760 | }
|
---|
| 761 |
|
---|
[63783] | 762 | /** @copydoc VDIMAGEBACKEND::pfnGetFileSize */
|
---|
[57388] | 763 | static DECLCALLBACK(uint64_t) parallelsGetFileSize(void *pBackendData)
|
---|
[21371] | 764 | {
|
---|
| 765 | LogFlowFunc(("pBackendData=%#p\n", pBackendData));
|
---|
| 766 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 767 | uint64_t cb = 0;
|
---|
| 768 |
|
---|
[63780] | 769 | AssertPtrReturn(pImage, 0);
|
---|
[21371] | 770 |
|
---|
[63780] | 771 | if (pImage->pStorage)
|
---|
[32536] | 772 | cb = pImage->cbFileCurrent;
|
---|
[21371] | 773 |
|
---|
| 774 | LogFlowFunc(("returns %lld\n", cb));
|
---|
| 775 | return cb;
|
---|
| 776 | }
|
---|
| 777 |
|
---|
[63783] | 778 | /** @copydoc VDIMAGEBACKEND::pfnGetPCHSGeometry */
|
---|
[57388] | 779 | static DECLCALLBACK(int) parallelsGetPCHSGeometry(void *pBackendData,
|
---|
| 780 | PVDGEOMETRY pPCHSGeometry)
|
---|
[21371] | 781 | {
|
---|
| 782 | LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p\n", pBackendData, pPCHSGeometry));
|
---|
| 783 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[63780] | 784 | int rc = VINF_SUCCESS;
|
---|
[21371] | 785 |
|
---|
[63780] | 786 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 787 |
|
---|
[63780] | 788 | if (pImage->PCHSGeometry.cCylinders)
|
---|
| 789 | *pPCHSGeometry = pImage->PCHSGeometry;
|
---|
[21371] | 790 | else
|
---|
[63780] | 791 | rc = VERR_VD_GEOMETRY_NOT_SET;
|
---|
[21371] | 792 |
|
---|
| 793 | LogFlowFunc(("returns %Rrc (PCHS=%u/%u/%u)\n", rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
|
---|
| 794 | return rc;
|
---|
| 795 | }
|
---|
| 796 |
|
---|
[63783] | 797 | /** @copydoc VDIMAGEBACKEND::pfnSetPCHSGeometry */
|
---|
[57388] | 798 | static DECLCALLBACK(int) parallelsSetPCHSGeometry(void *pBackendData,
|
---|
| 799 | PCVDGEOMETRY pPCHSGeometry)
|
---|
[21371] | 800 | {
|
---|
[63780] | 801 | LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData,
|
---|
| 802 | pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
|
---|
[21371] | 803 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[63780] | 804 | int rc = VINF_SUCCESS;
|
---|
[21371] | 805 |
|
---|
[63780] | 806 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 807 |
|
---|
[63780] | 808 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 809 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
| 810 | else
|
---|
[21371] | 811 | pImage->PCHSGeometry = *pPCHSGeometry;
|
---|
| 812 |
|
---|
| 813 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 814 | return rc;
|
---|
| 815 | }
|
---|
| 816 |
|
---|
[63783] | 817 | /** @copydoc VDIMAGEBACKEND::pfnGetLCHSGeometry */
|
---|
[57388] | 818 | static DECLCALLBACK(int) parallelsGetLCHSGeometry(void *pBackendData,
|
---|
| 819 | PVDGEOMETRY pLCHSGeometry)
|
---|
[21371] | 820 | {
|
---|
| 821 | LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p\n", pBackendData, pLCHSGeometry));
|
---|
| 822 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[63780] | 823 | int rc = VINF_SUCCESS;
|
---|
[21371] | 824 |
|
---|
[63780] | 825 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 826 |
|
---|
[63780] | 827 | if (pImage->LCHSGeometry.cCylinders)
|
---|
| 828 | *pLCHSGeometry = pImage->LCHSGeometry;
|
---|
[21371] | 829 | else
|
---|
[63780] | 830 | rc = VERR_VD_GEOMETRY_NOT_SET;
|
---|
[21371] | 831 |
|
---|
| 832 | LogFlowFunc(("returns %Rrc (LCHS=%u/%u/%u)\n", rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
|
---|
| 833 | return rc;
|
---|
| 834 | }
|
---|
| 835 |
|
---|
[63783] | 836 | /** @copydoc VDIMAGEBACKEND::pfnSetLCHSGeometry */
|
---|
[57388] | 837 | static DECLCALLBACK(int) parallelsSetLCHSGeometry(void *pBackendData,
|
---|
| 838 | PCVDGEOMETRY pLCHSGeometry)
|
---|
[21371] | 839 | {
|
---|
| 840 | LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
|
---|
| 841 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[63780] | 842 | int rc = VINF_SUCCESS;
|
---|
[21371] | 843 |
|
---|
[63780] | 844 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 845 |
|
---|
[63780] | 846 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 847 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
| 848 | else
|
---|
[21371] | 849 | pImage->LCHSGeometry = *pLCHSGeometry;
|
---|
| 850 |
|
---|
| 851 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 852 | return rc;
|
---|
| 853 | }
|
---|
| 854 |
|
---|
[66486] | 855 | /** @copydoc VDIMAGEBACKEND::pfnQueryRegions */
|
---|
| 856 | static DECLCALLBACK(int) parallelsQueryRegions(void *pBackendData, PCVDREGIONLIST *ppRegionList)
|
---|
| 857 | {
|
---|
| 858 | LogFlowFunc(("pBackendData=%#p ppRegionList=%#p\n", pBackendData, ppRegionList));
|
---|
| 859 | PPARALLELSIMAGE pThis = (PPARALLELSIMAGE)pBackendData;
|
---|
| 860 |
|
---|
| 861 | AssertPtrReturn(pThis, VERR_VD_NOT_OPENED);
|
---|
| 862 |
|
---|
| 863 | *ppRegionList = &pThis->RegionList;
|
---|
| 864 | LogFlowFunc(("returns %Rrc\n", VINF_SUCCESS));
|
---|
| 865 | return VINF_SUCCESS;
|
---|
| 866 | }
|
---|
| 867 |
|
---|
| 868 | /** @copydoc VDIMAGEBACKEND::pfnRegionListRelease */
|
---|
| 869 | static DECLCALLBACK(void) parallelsRegionListRelease(void *pBackendData, PCVDREGIONLIST pRegionList)
|
---|
| 870 | {
|
---|
| 871 | RT_NOREF1(pRegionList);
|
---|
| 872 | LogFlowFunc(("pBackendData=%#p pRegionList=%#p\n", pBackendData, pRegionList));
|
---|
| 873 | PPARALLELSIMAGE pThis = (PPARALLELSIMAGE)pBackendData;
|
---|
| 874 | AssertPtr(pThis); RT_NOREF(pThis);
|
---|
| 875 |
|
---|
| 876 | /* Nothing to do here. */
|
---|
| 877 | }
|
---|
| 878 |
|
---|
[63783] | 879 | /** @copydoc VDIMAGEBACKEND::pfnGetImageFlags */
|
---|
[57388] | 880 | static DECLCALLBACK(unsigned) parallelsGetImageFlags(void *pBackendData)
|
---|
[21371] | 881 | {
|
---|
| 882 | LogFlowFunc(("pBackendData=%#p\n", pBackendData));
|
---|
| 883 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 884 |
|
---|
[63780] | 885 | AssertPtrReturn(pImage, 0);
|
---|
[21371] | 886 |
|
---|
[63780] | 887 | LogFlowFunc(("returns %#x\n", pImage->uImageFlags));
|
---|
| 888 | return pImage->uImageFlags;
|
---|
[21371] | 889 | }
|
---|
| 890 |
|
---|
[63783] | 891 | /** @copydoc VDIMAGEBACKEND::pfnGetOpenFlags */
|
---|
[57388] | 892 | static DECLCALLBACK(unsigned) parallelsGetOpenFlags(void *pBackendData)
|
---|
[21371] | 893 | {
|
---|
| 894 | LogFlowFunc(("pBackendData=%#p\n", pBackendData));
|
---|
| 895 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 896 |
|
---|
[63780] | 897 | AssertPtrReturn(pImage, 0);
|
---|
[21371] | 898 |
|
---|
[63780] | 899 | LogFlowFunc(("returns %#x\n", pImage->uOpenFlags));
|
---|
| 900 | return pImage->uOpenFlags;
|
---|
[21371] | 901 | }
|
---|
| 902 |
|
---|
[63783] | 903 | /** @copydoc VDIMAGEBACKEND::pfnSetOpenFlags */
|
---|
[57388] | 904 | static DECLCALLBACK(int) parallelsSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
|
---|
[21371] | 905 | {
|
---|
| 906 | LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
|
---|
| 907 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
[63780] | 908 | int rc = VINF_SUCCESS;
|
---|
[21371] | 909 |
|
---|
[33182] | 910 | /* Image must be opened and the new flags must be valid. */
|
---|
[44232] | 911 | if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
|
---|
| 912 | | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
|
---|
| 913 | | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
|
---|
[63780] | 914 | rc = VERR_INVALID_PARAMETER;
|
---|
| 915 | else
|
---|
[21371] | 916 | {
|
---|
[63780] | 917 | /* Implement this operation via reopening the image. */
|
---|
| 918 | parallelsFreeImage(pImage, false);
|
---|
| 919 | rc = parallelsOpenImage(pImage, uOpenFlags);
|
---|
[21371] | 920 | }
|
---|
| 921 |
|
---|
| 922 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 923 | return rc;
|
---|
| 924 | }
|
---|
| 925 |
|
---|
[63783] | 926 | /** @copydoc VDIMAGEBACKEND::pfnGetComment */
|
---|
[57388] | 927 | static DECLCALLBACK(int) parallelsGetComment(void *pBackendData, char *pszComment,
|
---|
| 928 | size_t cbComment)
|
---|
[21371] | 929 | {
|
---|
[62751] | 930 | RT_NOREF2(pszComment, cbComment);
|
---|
[21371] | 931 | LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
|
---|
| 932 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 933 |
|
---|
[63780] | 934 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 935 |
|
---|
[63780] | 936 | LogFlowFunc(("returns %Rrc comment='%s'\n", VERR_NOT_SUPPORTED, pszComment));
|
---|
| 937 | return VERR_NOT_SUPPORTED;
|
---|
[21371] | 938 | }
|
---|
| 939 |
|
---|
[63783] | 940 | /** @copydoc VDIMAGEBACKEND::pfnSetComment */
|
---|
[57388] | 941 | static DECLCALLBACK(int) parallelsSetComment(void *pBackendData, const char *pszComment)
|
---|
[21371] | 942 | {
|
---|
[62751] | 943 | RT_NOREF1(pszComment);
|
---|
[21371] | 944 | LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
|
---|
| 945 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 946 |
|
---|
[63780] | 947 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 948 |
|
---|
[63780] | 949 | int rc;
|
---|
| 950 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 951 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
[21371] | 952 | else
|
---|
[63780] | 953 | rc = VERR_NOT_SUPPORTED;
|
---|
[21371] | 954 |
|
---|
| 955 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 956 | return rc;
|
---|
| 957 | }
|
---|
| 958 |
|
---|
[63783] | 959 | /** @copydoc VDIMAGEBACKEND::pfnGetUuid */
|
---|
[57388] | 960 | static DECLCALLBACK(int) parallelsGetUuid(void *pBackendData, PRTUUID pUuid)
|
---|
[21371] | 961 | {
|
---|
[62751] | 962 | RT_NOREF1(pUuid);
|
---|
[21371] | 963 | LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
|
---|
| 964 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 965 |
|
---|
[63780] | 966 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 967 |
|
---|
[63780] | 968 | LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
|
---|
| 969 | return VERR_NOT_SUPPORTED;
|
---|
[21371] | 970 | }
|
---|
| 971 |
|
---|
[63783] | 972 | /** @copydoc VDIMAGEBACKEND::pfnSetUuid */
|
---|
[57388] | 973 | static DECLCALLBACK(int) parallelsSetUuid(void *pBackendData, PCRTUUID pUuid)
|
---|
[21371] | 974 | {
|
---|
[62751] | 975 | RT_NOREF1(pUuid);
|
---|
[21371] | 976 | LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
|
---|
| 977 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 978 |
|
---|
[63780] | 979 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 980 |
|
---|
[63780] | 981 | int rc;
|
---|
| 982 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 983 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
[21371] | 984 | else
|
---|
[63780] | 985 | rc = VERR_NOT_SUPPORTED;
|
---|
[21371] | 986 |
|
---|
| 987 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 988 | return rc;
|
---|
| 989 | }
|
---|
| 990 |
|
---|
[63783] | 991 | /** @copydoc VDIMAGEBACKEND::pfnGetModificationUuid */
|
---|
[57388] | 992 | static DECLCALLBACK(int) parallelsGetModificationUuid(void *pBackendData, PRTUUID pUuid)
|
---|
[21371] | 993 | {
|
---|
[62751] | 994 | RT_NOREF1(pUuid);
|
---|
[21371] | 995 | LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
|
---|
| 996 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 997 |
|
---|
[63780] | 998 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 999 |
|
---|
[63780] | 1000 | LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
|
---|
| 1001 | return VERR_NOT_SUPPORTED;
|
---|
[21371] | 1002 | }
|
---|
| 1003 |
|
---|
[63783] | 1004 | /** @copydoc VDIMAGEBACKEND::pfnSetModificationUuid */
|
---|
[57388] | 1005 | static DECLCALLBACK(int) parallelsSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
|
---|
[21371] | 1006 | {
|
---|
[62751] | 1007 | RT_NOREF1(pUuid);
|
---|
[21371] | 1008 | LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
|
---|
| 1009 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 1010 |
|
---|
[63780] | 1011 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 1012 |
|
---|
[63780] | 1013 | int rc;
|
---|
| 1014 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 1015 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
[21371] | 1016 | else
|
---|
[63780] | 1017 | rc = VERR_NOT_SUPPORTED;
|
---|
[21371] | 1018 |
|
---|
| 1019 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 1020 | return rc;
|
---|
| 1021 | }
|
---|
| 1022 |
|
---|
[63783] | 1023 | /** @copydoc VDIMAGEBACKEND::pfnGetParentUuid */
|
---|
[57388] | 1024 | static DECLCALLBACK(int) parallelsGetParentUuid(void *pBackendData, PRTUUID pUuid)
|
---|
[21371] | 1025 | {
|
---|
[62751] | 1026 | RT_NOREF1(pUuid);
|
---|
[21371] | 1027 | LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
|
---|
| 1028 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 1029 |
|
---|
[63780] | 1030 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 1031 |
|
---|
[63780] | 1032 | LogFlowFunc(("returns %Rrc (%RTuuid)\n", VERR_NOT_SUPPORTED, pUuid));
|
---|
| 1033 | return VERR_NOT_SUPPORTED;
|
---|
[21371] | 1034 | }
|
---|
| 1035 |
|
---|
[63783] | 1036 | /** @copydoc VDIMAGEBACKEND::pfnSetParentUuid */
|
---|
[57388] | 1037 | static DECLCALLBACK(int) parallelsSetParentUuid(void *pBackendData, PCRTUUID pUuid)
|
---|
[21371] | 1038 | {
|
---|
[62751] | 1039 | RT_NOREF1(pUuid);
|
---|
[21371] | 1040 | LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
|
---|
| 1041 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 1042 |
|
---|
[63780] | 1043 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 1044 |
|
---|
[63780] | 1045 | int rc;
|
---|
| 1046 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 1047 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
[21371] | 1048 | else
|
---|
[63780] | 1049 | rc = VERR_NOT_SUPPORTED;
|
---|
[21371] | 1050 |
|
---|
| 1051 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 1052 | return rc;
|
---|
| 1053 | }
|
---|
| 1054 |
|
---|
[63783] | 1055 | /** @copydoc VDIMAGEBACKEND::pfnGetParentModificationUuid */
|
---|
[57388] | 1056 | static DECLCALLBACK(int) parallelsGetParentModificationUuid(void *pBackendData, PRTUUID pUuid)
|
---|
[21371] | 1057 | {
|
---|
[62751] | 1058 | RT_NOREF1(pUuid);
|
---|
[21371] | 1059 | LogFlowFunc(("pBackendData=%#p pUuid=%#p\n", pBackendData, pUuid));
|
---|
| 1060 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 1061 |
|
---|
[63780] | 1062 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 1063 |
|
---|
[63780] | 1064 | int rc;
|
---|
| 1065 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 1066 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
| 1067 | else
|
---|
[21371] | 1068 | rc = VERR_NOT_SUPPORTED;
|
---|
| 1069 |
|
---|
| 1070 | LogFlowFunc(("returns %Rrc (%RTuuid)\n", rc, pUuid));
|
---|
| 1071 | return rc;
|
---|
| 1072 | }
|
---|
| 1073 |
|
---|
[63783] | 1074 | /** @copydoc VDIMAGEBACKEND::pfnSetParentModificationUuid */
|
---|
[57388] | 1075 | static DECLCALLBACK(int) parallelsSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
|
---|
[21371] | 1076 | {
|
---|
[62751] | 1077 | RT_NOREF1(pUuid);
|
---|
[21371] | 1078 | LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
|
---|
| 1079 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 1080 |
|
---|
[63780] | 1081 | AssertPtrReturn(pImage, VERR_VD_NOT_OPENED);
|
---|
[21371] | 1082 |
|
---|
[63780] | 1083 | int rc;
|
---|
| 1084 | if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
|
---|
| 1085 | rc = VERR_VD_IMAGE_READ_ONLY;
|
---|
[21371] | 1086 | else
|
---|
[63780] | 1087 | rc = VERR_NOT_SUPPORTED;
|
---|
[21371] | 1088 |
|
---|
| 1089 | LogFlowFunc(("returns %Rrc\n", rc));
|
---|
| 1090 | return rc;
|
---|
| 1091 | }
|
---|
| 1092 |
|
---|
[63783] | 1093 | /** @copydoc VDIMAGEBACKEND::pfnDump */
|
---|
[57388] | 1094 | static DECLCALLBACK(void) parallelsDump(void *pBackendData)
|
---|
[21371] | 1095 | {
|
---|
| 1096 | PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
|
---|
| 1097 |
|
---|
[63780] | 1098 | AssertPtrReturnVoid(pImage);
|
---|
| 1099 | vdIfErrorMessage(pImage->pIfError, "Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u\n",
|
---|
| 1100 | pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
|
---|
| 1101 | pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors);
|
---|
[21371] | 1102 | }
|
---|
| 1103 |
|
---|
[30864] | 1104 |
|
---|
| 1105 |
|
---|
[63781] | 1106 | const VDIMAGEBACKEND g_ParallelsBackend =
|
---|
[21371] | 1107 | {
|
---|
[63905] | 1108 | /* u32Version */
|
---|
| 1109 | VD_IMGBACKEND_VERSION,
|
---|
[21371] | 1110 | /* pszBackendName */
|
---|
| 1111 | "Parallels",
|
---|
| 1112 | /* uBackendCaps */
|
---|
[38413] | 1113 | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_CREATE_DYNAMIC | VD_CAP_DIFF,
|
---|
[33524] | 1114 | /* paFileExtensions */
|
---|
| 1115 | s_aParallelsFileExtensions,
|
---|
[21371] | 1116 | /* paConfigInfo */
|
---|
| 1117 | NULL,
|
---|
[63802] | 1118 | /* pfnProbe */
|
---|
| 1119 | parallelsProbe,
|
---|
[21371] | 1120 | /* pfnOpen */
|
---|
| 1121 | parallelsOpen,
|
---|
| 1122 | /* pfnCreate */
|
---|
| 1123 | parallelsCreate,
|
---|
| 1124 | /* pfnRename */
|
---|
| 1125 | parallelsRename,
|
---|
| 1126 | /* pfnClose */
|
---|
| 1127 | parallelsClose,
|
---|
| 1128 | /* pfnRead */
|
---|
| 1129 | parallelsRead,
|
---|
| 1130 | /* pfnWrite */
|
---|
| 1131 | parallelsWrite,
|
---|
| 1132 | /* pfnFlush */
|
---|
| 1133 | parallelsFlush,
|
---|
[44252] | 1134 | /* pfnDiscard */
|
---|
| 1135 | NULL,
|
---|
[21371] | 1136 | /* pfnGetVersion */
|
---|
| 1137 | parallelsGetVersion,
|
---|
| 1138 | /* pfnGetFileSize */
|
---|
| 1139 | parallelsGetFileSize,
|
---|
| 1140 | /* pfnGetPCHSGeometry */
|
---|
| 1141 | parallelsGetPCHSGeometry,
|
---|
| 1142 | /* pfnSetPCHSGeometry */
|
---|
| 1143 | parallelsSetPCHSGeometry,
|
---|
| 1144 | /* pfnGetLCHSGeometry */
|
---|
| 1145 | parallelsGetLCHSGeometry,
|
---|
| 1146 | /* pfnSetLCHSGeometry */
|
---|
| 1147 | parallelsSetLCHSGeometry,
|
---|
[66110] | 1148 | /* pfnQueryRegions */
|
---|
[66486] | 1149 | parallelsQueryRegions,
|
---|
[66110] | 1150 | /* pfnRegionListRelease */
|
---|
[66486] | 1151 | parallelsRegionListRelease,
|
---|
[21371] | 1152 | /* pfnGetImageFlags */
|
---|
| 1153 | parallelsGetImageFlags,
|
---|
| 1154 | /* pfnGetOpenFlags */
|
---|
| 1155 | parallelsGetOpenFlags,
|
---|
| 1156 | /* pfnSetOpenFlags */
|
---|
| 1157 | parallelsSetOpenFlags,
|
---|
| 1158 | /* pfnGetComment */
|
---|
| 1159 | parallelsGetComment,
|
---|
| 1160 | /* pfnSetComment */
|
---|
| 1161 | parallelsSetComment,
|
---|
| 1162 | /* pfnGetUuid */
|
---|
| 1163 | parallelsGetUuid,
|
---|
| 1164 | /* pfnSetUuid */
|
---|
| 1165 | parallelsSetUuid,
|
---|
| 1166 | /* pfnGetModificationUuid */
|
---|
| 1167 | parallelsGetModificationUuid,
|
---|
| 1168 | /* pfnSetModificationUuid */
|
---|
| 1169 | parallelsSetModificationUuid,
|
---|
| 1170 | /* pfnGetParentUuid */
|
---|
| 1171 | parallelsGetParentUuid,
|
---|
| 1172 | /* pfnSetParentUuid */
|
---|
| 1173 | parallelsSetParentUuid,
|
---|
| 1174 | /* pfnGetParentModificationUuid */
|
---|
| 1175 | parallelsGetParentModificationUuid,
|
---|
| 1176 | /* pfnSetParentModificationUuid */
|
---|
| 1177 | parallelsSetParentModificationUuid,
|
---|
| 1178 | /* pfnDump */
|
---|
| 1179 | parallelsDump,
|
---|
[58132] | 1180 | /* pfnGetTimestamp */
|
---|
[32536] | 1181 | NULL,
|
---|
[58132] | 1182 | /* pfnGetParentTimestamp */
|
---|
[32536] | 1183 | NULL,
|
---|
[58132] | 1184 | /* pfnSetParentTimestamp */
|
---|
[32536] | 1185 | NULL,
|
---|
[21371] | 1186 | /* pfnGetParentFilename */
|
---|
[32536] | 1187 | NULL,
|
---|
[21371] | 1188 | /* pfnSetParentFilename */
|
---|
[32536] | 1189 | NULL,
|
---|
[21371] | 1190 | /* pfnComposeLocation */
|
---|
| 1191 | genericFileComposeLocation,
|
---|
| 1192 | /* pfnComposeName */
|
---|
[26291] | 1193 | genericFileComposeName,
|
---|
| 1194 | /* pfnCompact */
|
---|
[31776] | 1195 | NULL,
|
---|
| 1196 | /* pfnResize */
|
---|
[44101] | 1197 | NULL,
|
---|
| 1198 | /* pfnRepair */
|
---|
[50988] | 1199 | NULL,
|
---|
| 1200 | /* pfnTraverseMetadata */
|
---|
[63905] | 1201 | NULL,
|
---|
| 1202 | /* u32VersionEnd */
|
---|
| 1203 | VD_IMGBACKEND_VERSION
|
---|
[21371] | 1204 | };
|
---|