VirtualBox

Changeset 32573 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Sep 16, 2010 5:18:03 PM (14 years ago)
Author:
vboxsync
Message:

Storage/Vmdk: implement special purpose backend for proper streamOptimized VMDK export, at the moment only with the functionality needed by cloning. Not really tested.

Location:
trunk/src/VBox/Devices/Storage
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r32553 r32573  
    418418extern VBOXHDDBACKEND g_RawBackend;
    419419extern VBOXHDDBACKEND g_VmdkBackend;
     420extern VBOXHDDBACKEND g_VmdkStreamBackend;
    420421extern VBOXHDDBACKEND g_VDIBackend;
    421422extern VBOXHDDBACKEND g_VhdBackend;
     
    434435    &g_RawBackend,
    435436    &g_VmdkBackend,
     437    &g_VmdkStreamBackend,
    436438    &g_VDIBackend,
    437439    &g_VhdBackend,
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r32553 r32573  
    12061206    }
    12071207    pExtent->pGD = pGD;
    1208     /* The VMDK 1.1 spec talks about compressed grain directories, but real
    1209      * life files don't have them. The spec is wrong in creative ways. */
     1208    /* The VMDK 1.1 spec seems to talk about compressed grain directories,
     1209     * but in reality they are not compressed. */
    12101210    rc = vmdkFileReadSync(pImage, pExtent->pFile,
    12111211                          VMDK_SECTOR2BYTE(pExtent->uSectorGD),
     
    12291229        }
    12301230        pExtent->pRGD = pRGD;
    1231         /* The VMDK 1.1 spec talks about compressed grain directories, but real
    1232          * life files don't have them. The spec is wrong in creative ways. */
     1231        /* The VMDK 1.1 spec seems to talk about compressed grain directories,
     1232         * but in reality they are not compressed. */
    12331233        rc = vmdkFileReadSync(pImage, pExtent->pFile,
    12341234                              VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
     
    12771277                goto out;
    12781278            }
    1279             /* The VMDK 1.1 spec talks about compressed grain tables, but real
    1280              * life files don't have them. The spec is wrong in creative ways. */
     1279            /* The VMDK 1.1 spec seems to talk about compressed grain tables,
     1280             * but in reality they are not compressed. */
    12811281            rc = vmdkFileReadSync(pImage, pExtent->pFile,
    12821282                                  VMDK_SECTOR2BYTE(*pGDTmp),
     
    12891289                goto out;
    12901290            }
    1291             /* The VMDK 1.1 spec talks about compressed grain tables, but real
    1292              * life files don't have them. The spec is wrong in creative ways. */
     1291            /* The VMDK 1.1 spec seems to talk about compressed grain tables,
     1292             * but in reality they are not compressed. */
    12931293            rc = vmdkFileReadSync(pImage, pExtent->pFile,
    12941294                                  VMDK_SECTOR2BYTE(*pRGDTmp),
     
    13321332                continue;
    13331333
    1334             /* The VMDK 1.1 spec talks about compressed grain tables, but real
    1335              * life files don't have them. The spec is wrong in creative ways. */
     1334            /* The VMDK 1.1 spec seems to talk about compressed grain tables,
     1335             * but in reality they are not compressed. */
    13361336            rc = vmdkFileReadSync(pImage, pExtent->pFile,
    13371337                                  VMDK_SECTOR2BYTE(*pGDTmp),
     
    28682868        goto out;
    28692869    }
    2870 /* disabled the size check again as there are too many too short vmdks out there */
     2870/* disabled the check as there are too many truncated vmdk images out there */
    28712871#ifdef VBOX_WITH_VMDK_STRICT_SIZE_CHECK
    28722872    if (    cbExtentSize != RT_ALIGN_64(cbExtentSize, 512)
     
    40464046    if (RT_FAILURE(rc))
    40474047        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
     4048    return rc;
     4049}
     4050
     4051/**
     4052 * Internal. Clear the grain table buffer for real stream optimized writing.
     4053 */
     4054static void vmdksClearGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent)
     4055{
     4056    uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
     4057    for (uint32_t i = 0; i < cCacheLines; i++)
     4058        memset(&pImage->pGTCache->aGTCache[i].aGTData[0], '\0',
     4059               VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t));
     4060}
     4061
     4062/**
     4063 * Internal. Flush the grain table buffer for real stream optimized writing.
     4064 */
     4065static int vmdksFlushGT(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
     4066                        uint32_t uGDEntry)
     4067{
     4068    int rc = VINF_SUCCESS;
     4069    uint32_t cCacheLines = RT_ALIGN(pExtent->cGTEntries, VMDK_GT_CACHELINE_SIZE) / VMDK_GT_CACHELINE_SIZE;
     4070
     4071    uint64_t uFileOffset;
     4072    rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset);
     4073    AssertRC(rc);
     4074    uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     4075
     4076    /* Grain table marker. */
     4077    /** @todo check me! */
     4078    uint8_t aMarker[512];
     4079    memset(aMarker, '\0', sizeof(aMarker));
     4080    PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
     4081    pMarker->cbSize = RT_H2LE_U32(pExtent->cGTEntries * sizeof(uint32_t));
     4082    pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GT);
     4083    rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4084                           aMarker, sizeof(aMarker), NULL);
     4085    AssertRC(rc);
     4086    uFileOffset += 512;
     4087
     4088    if (!pExtent->pGD || pExtent->pGD[uGDEntry])
     4089        return VERR_INTERNAL_ERROR;
     4090
     4091    pExtent->pGD[uGDEntry] = VMDK_BYTE2SECTOR(uFileOffset);
     4092
     4093    for (uint32_t i = 0; i < cCacheLines; i++)
     4094    {
     4095        /* Convert the grain table to little endian in place, as it will not
     4096         * be used at all after this function has been called. */
     4097        uint32_t *pGTTmp = &pImage->pGTCache->aGTCache[i].aGTData[0];
     4098        for (uint32_t j = 0; j < VMDK_GT_CACHELINE_SIZE; j++, pGTTmp++)
     4099            *pGTTmp = RT_H2LE_U32(*pGTTmp);
     4100
     4101        rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4102                               &pImage->pGTCache->aGTCache[i].aGTData[0],
     4103                               VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t),
     4104                               NULL);
     4105    }
     4106    return rc;
     4107}
     4108
     4109/**
     4110 * Internal. Free all allocated space for representing a real stream optimized
     4111 * image, and optionally delete the image from disk.
     4112 */
     4113static int vmdksFreeImage(PVMDKIMAGE pImage, bool fDelete)
     4114{
     4115    int rc = VINF_SUCCESS;
     4116
     4117    /* Freeing a never allocated image (e.g. because the open failed) is
     4118     * not signalled as an error. After all nothing bad happens. */
     4119    if (pImage)
     4120    {
     4121        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     4122        {
     4123            /* Check if all extents are clean. */
     4124            for (unsigned i = 0; i < pImage->cExtents; i++)
     4125            {
     4126                Assert(!pImage->pExtents[i].fUncleanShutdown);
     4127            }
     4128        }
     4129
     4130        /* No need to write any pending data if the file will be deleted. */
     4131        if (!fDelete && pImage->pExtents)
     4132        {
     4133            PVMDKEXTENT pExtent = &pImage->pExtents[0];
     4134            uint32_t uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries;
     4135            if (uLastGDEntry != pExtent->cGDEntries)
     4136            {
     4137                rc = vmdksFlushGT(pImage, pExtent, uLastGDEntry);
     4138                AssertRC(rc);
     4139                vmdksClearGT(pImage, pExtent);
     4140                for (uint32_t i = uLastGDEntry + 1; i < pExtent->cGDEntries; i++)
     4141                {
     4142                    rc = vmdksFlushGT(pImage, pExtent, i);
     4143                    AssertRC(rc);
     4144                }
     4145            }
     4146
     4147            uint64_t uFileOffset;
     4148            rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset);
     4149            AssertRC(rc);
     4150            uFileOffset = RT_ALIGN_64(uFileOffset, 512);
     4151
     4152            /* Grain directory marker. */
     4153            /** @todo check me! */
     4154            uint8_t aMarker[512];
     4155            memset(aMarker, '\0', sizeof(aMarker));
     4156            PVMDKMARKER pMarker = (PVMDKMARKER)&aMarker[0];
     4157            pMarker->cbSize = RT_H2LE_U32(pExtent->cGDEntries * sizeof(uint32_t));
     4158            pMarker->uType = RT_H2LE_U32(VMDK_MARKER_GD);
     4159            rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4160                                   aMarker, sizeof(aMarker), NULL);
     4161            AssertRC(rc);
     4162            uFileOffset += 512;
     4163
     4164            /* Write grain directory in little endian style. The array will
     4165             * not be used after this, so convert in place. */
     4166            uint32_t *pGDTmp = pExtent->pGD;
     4167            for (uint32_t i = 0; i < pExtent->cGDEntries; i++, pGDTmp++)
     4168                *pGDTmp = RT_H2LE_U32(*pGDTmp);
     4169            rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4170                                   pExtent->pGD,
     4171                                   pExtent->cGDEntries * sizeof(uint32_t),
     4172                                   NULL);
     4173            AssertRC(rc);
     4174
     4175            pExtent->uSectorGD = VMDK_BYTE2SECTOR(uFileOffset);
     4176            pExtent->uSectorRGD = VMDK_BYTE2SECTOR(uFileOffset);
     4177            uFileOffset = RT_ALIGN_64(uFileOffset + pExtent->cGDEntries * sizeof(uint32_t), 512);
     4178
     4179            /* End of stream marker. */
     4180            memset(aMarker, '\0', sizeof(aMarker));
     4181            /** @todo check me! */
     4182            rc = vmdkFileWriteSync(pImage, pExtent->pFile, uFileOffset,
     4183                                   aMarker, sizeof(aMarker), NULL);
     4184            AssertRC(rc);
     4185
     4186            uFileOffset += 512;
     4187            rc = vmdkWriteMetaSparseExtent(pImage, pExtent, uFileOffset);
     4188            AssertRC(rc);
     4189        }
     4190
     4191        if (pImage->pExtents != NULL)
     4192        {
     4193            for (unsigned i = 0 ; i < pImage->cExtents; i++)
     4194                vmdkFreeExtentData(pImage, &pImage->pExtents[i], fDelete);
     4195            RTMemFree(pImage->pExtents);
     4196            pImage->pExtents = NULL;
     4197        }
     4198        pImage->cExtents = 0;
     4199        if (pImage->pFile != NULL)
     4200            vmdkFileClose(pImage, &pImage->pFile, fDelete);
     4201        vmdkFileCheckAllClose(pImage);
     4202
     4203        if (pImage->pGTCache)
     4204        {
     4205            RTMemFree(pImage->pGTCache);
     4206            pImage->pGTCache = NULL;
     4207        }
     4208        if (pImage->pDescData)
     4209        {
     4210            RTMemFree(pImage->pDescData);
     4211            pImage->pDescData = NULL;
     4212        }
     4213    }
     4214
     4215    LogFlowFunc(("returns %Rrc\n", rc));
     4216    return rc;
     4217}
     4218
     4219/**
     4220 * Internal: Create a real stream optimized VMDK using only linear writes.
     4221 */
     4222static int vmdksCreateImage(PVMDKIMAGE pImage, uint64_t cbSize,
     4223                            unsigned uImageFlags, const char *pszComment,
     4224                            PCVDGEOMETRY pPCHSGeometry,
     4225                            PCVDGEOMETRY pLCHSGeometry, PCRTUUID pUuid,
     4226                            PFNVDPROGRESS pfnProgress, void *pvUser,
     4227                            unsigned uPercentStart, unsigned uPercentSpan)
     4228{
     4229    int rc;
     4230
     4231    pImage->uImageFlags = uImageFlags;
     4232
     4233    /* Try to get error interface. */
     4234    pImage->pInterfaceError = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_ERROR);
     4235    if (pImage->pInterfaceError)
     4236        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
     4237
     4238    /* Get I/O interface. */
     4239    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
     4240    AssertPtrReturn(pImage->pInterfaceIO, VERR_INVALID_PARAMETER);
     4241    pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     4242    AssertPtrReturn(pImage->pInterfaceIOCallbacks, VERR_INVALID_PARAMETER);
     4243
     4244    PVMDKEXTENT pExtent;
     4245    char *pszBasenameSubstr, *pszBasedirectory, *pszBasename;
     4246    size_t cbBasenameSubstr;
     4247
     4248    rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
     4249                              &pImage->Descriptor);
     4250    if (RT_FAILURE(rc))
     4251    {
     4252        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pImage->pszFilename);
     4253        goto out;
     4254    }
     4255
     4256    rc = vmdkCreateExtents(pImage, 1);
     4257    if (RT_FAILURE(rc))
     4258    {
     4259        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pImage->pszFilename);
     4260        goto out;
     4261    }
     4262
     4263    /* Basename strings needed for constructing the extent names. */
     4264    pszBasenameSubstr = RTPathFilename(pImage->pszFilename);
     4265    AssertPtr(pszBasenameSubstr);
     4266    cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
     4267
     4268    /* No separate descriptor file. */
     4269    pImage->pFile = NULL;
     4270
     4271    /* Set up all extents. */
     4272    pExtent = &pImage->pExtents[0];
     4273
     4274    /* Set up fullname/basename for extent description. Cannot use StrDup
     4275     * for basename, as it is not guaranteed that the memory can be freed
     4276     * with RTMemTmpFree, which must be used as in other code paths
     4277     * StrDup is not usable. */
     4278    pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
     4279    if (!pszBasename)
     4280    {
     4281        rc = VERR_NO_MEMORY;
     4282        goto out;
     4283    }
     4284    memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
     4285    pExtent->pszBasename = pszBasename;
     4286
     4287    pszBasedirectory = RTStrDup(pImage->pszFilename);
     4288    RTPathStripFilename(pszBasedirectory);
     4289    char *pszFullname;
     4290    rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszBasedirectory,
     4291                      RTPATH_SLASH, pExtent->pszBasename);
     4292    RTStrFree(pszBasedirectory);
     4293    if (RT_FAILURE(rc))
     4294        goto out;
     4295    pExtent->pszFullname = pszFullname;
     4296
     4297    /* Create file for extent. */
     4298    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
     4299                      VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags,
     4300                                                 true /* fCreate */),
     4301                      false /* fAsyncIO */);
     4302    if (RT_FAILURE(rc))
     4303    {
     4304        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
     4305        goto out;
     4306    }
     4307
     4308    /* Place descriptor file information. */
     4309    pExtent->uDescriptorSector = 1;
     4310    pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
     4311    /* The descriptor is part of the (only) extent. */
     4312    pExtent->pDescData = pImage->pDescData;
     4313    pImage->pDescData = NULL;
     4314
     4315    uint64_t cSectorsPerGDE, cSectorsPerGD;
     4316    pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     4317    pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, _64K));
     4318    pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(_64K);
     4319    pExtent->cGTEntries = 512;
     4320    cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     4321    pExtent->cSectorsPerGDE = cSectorsPerGDE;
     4322    pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     4323    cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     4324
     4325    /* The spec says version is 1 for all VMDKs, but the vast
     4326     * majority of streamOptimized VMDKs actually contain
     4327     * version 3 - so go with the majority. Both are acepted. */
     4328    pExtent->uVersion = 3;
     4329    pExtent->uCompression = VMDK_COMPRESSION_DEFLATE;
     4330    pExtent->fFooter = true;
     4331
     4332    pExtent->enmAccess = VMDKACCESS_READONLY;
     4333    pExtent->fUncleanShutdown = true;
     4334    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     4335    pExtent->uSectorOffset = 0;
     4336    pExtent->fMetaDirty = true;
     4337
     4338    /* Create grain directory, without preallocating it straight away. It will
     4339     * be constructed on the fly when writing out the data and written when
     4340     * closing the image. The end effect is that the full grain directory is
     4341     * allocated, which is a requirement of the VMDK specs. */
     4342    rc = vmdkCreateGrainDirectory(pImage, pExtent,
     4343                                  RT_MAX(  pExtent->uDescriptorSector
     4344                                         + pExtent->cDescriptorSectors,
     4345                                         1),
     4346                                  false /* fPreAlloc */);
     4347    if (RT_FAILURE(rc))
     4348    {
     4349        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
     4350        goto out;
     4351    }
     4352
     4353    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
     4354                            "streamOptimized");
     4355    if (RT_FAILURE(rc))
     4356    {
     4357        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pImage->pszFilename);
     4358        goto out;
     4359    }
     4360
     4361    if (pfnProgress)
     4362        pfnProgress(pvUser, uPercentStart + uPercentSpan * 20 / 100);
     4363
     4364    pImage->cbSize = cbSize;
     4365
     4366    Assert(pImage->cExtents == 1);
     4367
     4368    rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
     4369                           pExtent->cNominalSectors, pExtent->enmType,
     4370                           pExtent->pszBasename, pExtent->uSectorOffset);
     4371    if (RT_FAILURE(rc))
     4372    {
     4373        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not insert the extent list into descriptor in '%s'"), pImage->pszFilename);
     4374        goto out;
     4375    }
     4376    vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
     4377
     4378    if (    pPCHSGeometry->cCylinders != 0
     4379        &&  pPCHSGeometry->cHeads != 0
     4380        &&  pPCHSGeometry->cSectors != 0)
     4381    {
     4382        rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
     4383        if (RT_FAILURE(rc))
     4384            goto out;
     4385    }
     4386    if (    pLCHSGeometry->cCylinders != 0
     4387        &&  pLCHSGeometry->cHeads != 0
     4388        &&  pLCHSGeometry->cSectors != 0)
     4389    {
     4390        rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
     4391        if (RT_FAILURE(rc))
     4392            goto out;
     4393    }
     4394
     4395    pImage->LCHSGeometry = *pLCHSGeometry;
     4396    pImage->PCHSGeometry = *pPCHSGeometry;
     4397
     4398    pImage->ImageUuid = *pUuid;
     4399    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4400                            VMDK_DDB_IMAGE_UUID, &pImage->ImageUuid);
     4401    if (RT_FAILURE(rc))
     4402    {
     4403        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image UUID in new descriptor in '%s'"), pImage->pszFilename);
     4404        goto out;
     4405    }
     4406    RTUuidClear(&pImage->ParentUuid);
     4407    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4408                            VMDK_DDB_PARENT_UUID, &pImage->ParentUuid);
     4409    if (RT_FAILURE(rc))
     4410    {
     4411        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent image UUID in new descriptor in '%s'"), pImage->pszFilename);
     4412        goto out;
     4413    }
     4414    RTUuidClear(&pImage->ModificationUuid);
     4415    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4416                            VMDK_DDB_MODIFICATION_UUID,
     4417                            &pImage->ModificationUuid);
     4418    if (RT_FAILURE(rc))
     4419    {
     4420        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing modification UUID in new descriptor in '%s'"), pImage->pszFilename);
     4421        goto out;
     4422    }
     4423    RTUuidClear(&pImage->ParentModificationUuid);
     4424    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
     4425                            VMDK_DDB_PARENT_MODIFICATION_UUID,
     4426                            &pImage->ParentModificationUuid);
     4427    if (RT_FAILURE(rc))
     4428    {
     4429        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing parent modification UUID in new descriptor in '%s'"), pImage->pszFilename);
     4430        goto out;
     4431    }
     4432
     4433    rc = vmdkAllocateGrainTableCache(pImage);
     4434    if (RT_FAILURE(rc))
     4435        goto out;
     4436
     4437    rc = vmdkSetImageComment(pImage, pszComment);
     4438    if (RT_FAILURE(rc))
     4439    {
     4440        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot set image comment in '%s'"), pImage->pszFilename);
     4441        goto out;
     4442    }
     4443
     4444    if (pfnProgress)
     4445        pfnProgress(pvUser, uPercentStart + uPercentSpan * 50 / 100);
     4446
     4447    rc = vmdkWriteMetaSparseExtent(pImage, &pImage->pExtents[0], 0);
     4448    if (RT_FAILURE(rc))
     4449    {
     4450        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK header in '%s'"), pImage->pszFilename);
     4451        goto out;
     4452    }
     4453
     4454    if (pfnProgress)
     4455        pfnProgress(pvUser, uPercentStart + uPercentSpan * 70 / 100);
     4456
     4457    rc = vmdkWriteDescriptor(pImage);
     4458    if (RT_FAILURE(rc))
     4459    {
     4460        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write VMDK descriptor in '%s'"), pImage->pszFilename);
     4461        goto out;
     4462    }
     4463
     4464out:
     4465    if (RT_SUCCESS(rc) && pfnProgress)
     4466        pfnProgress(pvUser, uPercentStart + uPercentSpan);
     4467
     4468    if (RT_FAILURE(rc))
     4469        vmdksFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
    40484470    return rc;
    40494471}
     
    51955617    }
    51965618    return pszNewStr;
     5619}
     5620
     5621
     5622/** @copydoc VBOXHDDBACKEND::pfnCheckIfValid */
     5623static int vmdksCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
     5624                             PVDINTERFACE pVDIfsImage)
     5625{
     5626    LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
     5627    int rc = VINF_SUCCESS;
     5628
     5629    if (   !VALID_PTR(pszFilename)
     5630        || !*pszFilename
     5631        || strchr(pszFilename, '"'))
     5632    {
     5633        rc = VERR_INVALID_PARAMETER;
     5634        goto out;
     5635    }
     5636
     5637    /* Always return failure, to avoid opening other VMDK files via this
     5638     * special VMDK streamOptimized format backend. */
     5639    rc = VERR_NOT_SUPPORTED;
     5640
     5641out:
     5642    LogFlowFunc(("returns %Rrc\n", rc));
     5643    return rc;
     5644}
     5645
     5646
     5647/** @copydoc VBOXHDDBACKEND::pfnOpen */
     5648static int vmdksOpen(const char *pszFilename, unsigned uOpenFlags,
     5649                     PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
     5650                     void **ppBackendData)
     5651{
     5652    LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
     5653    int rc;
     5654
     5655    rc = VERR_NOT_SUPPORTED;
     5656    LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
     5657    return rc;
     5658}
     5659
     5660/** @copydoc VBOXHDDBACKEND::pfnCreate */
     5661static int vmdksCreate(const char *pszFilename, uint64_t cbSize,
     5662                       unsigned uImageFlags, const char *pszComment,
     5663                       PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry,
     5664                       PCRTUUID pUuid, unsigned uOpenFlags,
     5665                       unsigned uPercentStart, unsigned uPercentSpan,
     5666                       PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
     5667                       PVDINTERFACE pVDIfsOperation, void **ppBackendData)
     5668{
     5669    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 ppBackendData=%#p", pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
     5670    int rc;
     5671    PVMDKIMAGE pImage;
     5672
     5673    PFNVDPROGRESS pfnProgress = NULL;
     5674    void *pvUser = NULL;
     5675    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     5676                                              VDINTERFACETYPE_PROGRESS);
     5677    PVDINTERFACEPROGRESS pCbProgress = NULL;
     5678    if (pIfProgress)
     5679    {
     5680        pCbProgress = VDGetInterfaceProgress(pIfProgress);
     5681        pfnProgress = pCbProgress->pfnProgress;
     5682        pvUser = pIfProgress->pvUser;
     5683    }
     5684
     5685    /* Check open flags. No flags are supported. */
     5686    if (uOpenFlags != VD_OPEN_FLAGS_NORMAL)
     5687    {
     5688        rc = VERR_INVALID_PARAMETER;
     5689        goto out;
     5690    }
     5691
     5692    /* Check image flags. No flags are supported. */
     5693    if (uImageFlags != VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     5694    {
     5695        rc = VERR_INVALID_PARAMETER;
     5696        goto out;
     5697    }
     5698
     5699    /* Check size. Maximum 2TB-64K. */
     5700    if (   !cbSize
     5701        || cbSize >= _1T * 2 - _64K)
     5702    {
     5703        rc = VERR_VD_INVALID_SIZE;
     5704        goto out;
     5705    }
     5706
     5707    /* Check remaining arguments. */
     5708    if (   !VALID_PTR(pszFilename)
     5709        || !*pszFilename
     5710        || strchr(pszFilename, '"')
     5711        || !VALID_PTR(pPCHSGeometry)
     5712        || !VALID_PTR(pLCHSGeometry))
     5713    {
     5714        rc = VERR_INVALID_PARAMETER;
     5715        goto out;
     5716    }
     5717
     5718    pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
     5719    if (!pImage)
     5720    {
     5721        rc = VERR_NO_MEMORY;
     5722        goto out;
     5723    }
     5724    pImage->pszFilename = pszFilename;
     5725    pImage->pFile = NULL;
     5726    pImage->pExtents = NULL;
     5727    pImage->pFiles = NULL;
     5728    pImage->pGTCache = NULL;
     5729    pImage->pDescData = NULL;
     5730    pImage->pVDIfsDisk = pVDIfsDisk;
     5731    pImage->pVDIfsImage = pVDIfsImage;
     5732    /* Descriptors for stream optimized images are small, so don't waste
     5733     * space in the resulting image and allocate a small buffer. */
     5734    pImage->cbDescAlloc = VMDK_SECTOR2BYTE(4);
     5735    pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
     5736    if (!pImage->pDescData)
     5737    {
     5738        rc = VERR_NO_MEMORY;
     5739        goto out;
     5740    }
     5741
     5742    rc = vmdksCreateImage(pImage, cbSize, uImageFlags, pszComment,
     5743                          pPCHSGeometry, pLCHSGeometry, pUuid,
     5744                          pfnProgress, pvUser, uPercentStart, uPercentSpan);
     5745    if (RT_SUCCESS(rc))
     5746    {
     5747        /* Image is always writable. */
     5748        *ppBackendData = pImage;
     5749    }
     5750    else
     5751    {
     5752        RTMemFree(pImage->pDescData);
     5753        RTMemFree(pImage);
     5754    }
     5755
     5756out:
     5757    LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
     5758    return rc;
     5759}
     5760
     5761/** @copydoc VBOXHDDBACKEND::pfnClose */
     5762static int vmdksClose(void *pBackendData, bool fDelete)
     5763{
     5764    LogFlowFunc(("pBackendData=%#p fDelete=%d\n", pBackendData, fDelete));
     5765    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     5766    int rc;
     5767
     5768    rc = vmdksFreeImage(pImage, fDelete);
     5769    RTMemFree(pImage);
     5770
     5771    LogFlowFunc(("returns %Rrc\n", rc));
     5772    return rc;
     5773}
     5774
     5775/** @copydoc VBOXHDDBACKEND::pfnRead */
     5776static int vmdksRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
     5777                     size_t cbToRead, size_t *pcbActuallyRead)
     5778{
     5779    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToRead=%zu pcbActuallyRead=%#p\n", pBackendData, uOffset, pvBuf, cbToRead, pcbActuallyRead));
     5780    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     5781    int rc;
     5782
     5783    rc = VERR_NOT_SUPPORTED;
     5784    LogFlowFunc(("returns %Rrc\n", rc));
     5785    return rc;
     5786}
     5787
     5788/** @copydoc VBOXHDDBACKEND::pfnWrite */
     5789static int vmdksWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
     5790                      size_t cbToWrite, size_t *pcbWriteProcess,
     5791                      size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
     5792{
     5793    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
     5794    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     5795    PVMDKEXTENT pExtent;
     5796    uint64_t uSector;
     5797    uint32_t uGrain;
     5798    uint32_t uGDEntry, uLastGDEntry;
     5799    uint32_t cbGrain = 0;
     5800    uint32_t uCacheLine, uCacheEntry;
     5801    const void *pData = pvBuf;
     5802    int rc;
     5803
     5804    AssertPtr(pImage);
     5805    Assert(uOffset % 512 == 0);
     5806    Assert(cbToWrite % 512 == 0);
     5807
     5808    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     5809    {
     5810        rc = VERR_VD_IMAGE_READ_ONLY;
     5811        goto out;
     5812    }
     5813
     5814    pExtent = &pImage->pExtents[0];
     5815    uSector = VMDK_BYTE2SECTOR(uOffset);
     5816
     5817    /* Very strict requirements: always write at least one full grain, with
     5818     * proper alignment. Everything else would require reading of already
     5819     * written data, which we don't support for obvious reasons. The only
     5820     * exception is the last grain, and only if the image size specifies
     5821     * that only some portion holds data. In any case the write must be
     5822     * within the image limits, no "overshoot" allowed. */
     5823    if (   cbToWrite == 0
     5824        || (   cbToWrite < VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
     5825            && pImage->cbSize - uOffset >= VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
     5826        || uOffset % VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)
     5827        || uOffset + cbToWrite > pImage->cbSize)
     5828    {
     5829        rc = VERR_INVALID_PARAMETER;
     5830        goto out;
     5831    }
     5832
     5833    /* Clip write range to at most the rest of the grain. */
     5834    cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSector % pExtent->cSectorsPerGrain));
     5835
     5836    /* Do not allow to go back. */
     5837    uGrain = VMDK_BYTE2SECTOR(uOffset) / pExtent->cSectorsPerGrain;
     5838    uCacheLine = uGrain / VMDK_GT_CACHELINE_SIZE % VMDK_GT_CACHE_SIZE;
     5839    uCacheEntry = uGrain % VMDK_GT_CACHELINE_SIZE;
     5840    uGDEntry = uGrain / pExtent->cGTEntries;
     5841    uLastGDEntry = pExtent->uLastGrainWritten / pExtent->cGTEntries;
     5842    if (uGrain < pExtent->uLastGrainWritten)
     5843    {
     5844        rc = VERR_VD_VMDK_INVALID_WRITE;
     5845        goto out;
     5846    }
     5847
     5848    if (uGDEntry != uLastGDEntry)
     5849    {
     5850        rc = vmdksFlushGT(pImage, pExtent, uLastGDEntry);
     5851        if (RT_FAILURE(rc))
     5852            goto out;
     5853        vmdksClearGT(pImage, pExtent);
     5854        for (uint32_t i = uLastGDEntry + 1; i < uGDEntry; i++)
     5855        {
     5856            rc = vmdksFlushGT(pImage, pExtent, i);
     5857            if (RT_FAILURE(rc))
     5858                goto out;
     5859        }
     5860    }
     5861
     5862    /* Check access permissions as defined in the extent descriptor.
     5863     * May sound a bit paradoxical, but we created the image with a
     5864     * readonly extent since the resulting image is kind of "write once". */
     5865    if (pExtent->enmAccess != VMDKACCESS_READONLY)
     5866    {
     5867        rc = VERR_VD_VMDK_INVALID_STATE;
     5868        goto out;
     5869    }
     5870
     5871    uint64_t uFileOffset;
     5872    rc = vmdkFileGetSize(pImage, pExtent->pFile, &uFileOffset);
     5873    if (RT_FAILURE(rc))
     5874        goto out;
     5875    if (uFileOffset % 512)
     5876    {
     5877        rc = VERR_INTERNAL_ERROR;
     5878        goto out;
     5879    }
     5880
     5881    /* Paranoia check: extent type, grain table buffer presence and
     5882     * grain table buffer space. Also grain table entry must be clear. */
     5883    if (   pExtent->enmType != VMDKETYPE_HOSTED_SPARSE
     5884        || !pImage->pGTCache
     5885        || pExtent->cGTEntries > VMDK_GT_CACHE_SIZE * VMDK_GT_CACHELINE_SIZE
     5886        || pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry])
     5887    {
     5888        rc = VERR_INTERNAL_ERROR;
     5889        goto out;
     5890    }
     5891
     5892    /* Update grain table entry. */
     5893    pImage->pGTCache->aGTCache[uCacheLine].aGTData[uCacheEntry] = VMDK_BYTE2SECTOR(uFileOffset);
     5894
     5895    if (cbToWrite != VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
     5896    {
     5897        memcpy(pExtent->pvGrain, pvBuf, cbToWrite);
     5898        memset((char *)pExtent->pvGrain + cbToWrite, '\0',
     5899               VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbToWrite);
     5900        pData = pExtent->pvGrain;
     5901    }
     5902    rc = vmdkFileDeflateSync(pImage, pExtent->pFile, uFileOffset,
     5903                             pData, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain),
     5904                             VMDK_MARKER_IGNORE, uSector, &cbGrain);
     5905    if (RT_FAILURE(rc))
     5906    {
     5907        pExtent->uGrainSector = 0;
     5908        pExtent->uLastGrainSector = 0;
     5909        AssertRC(rc);
     5910        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: cannot write compressed data block in '%s'"), pExtent->pszFullname);
     5911    }
     5912    cbGrain = RT_ALIGN(cbGrain, 512);
     5913    pExtent->uLastGrainSector = VMDK_BYTE2SECTOR(uFileOffset);
     5914    pExtent->uLastGrainWritten = uGrain;
     5915    pExtent->cbLastGrainWritten = cbGrain;
     5916
     5917    if (pcbWriteProcess)
     5918        *pcbWriteProcess = cbToWrite;
     5919
     5920out:
     5921    LogFlowFunc(("returns %Rrc\n", rc));
     5922    return rc;
     5923}
     5924
     5925/** @copydoc VBOXHDDBACKEND::pfnFlush */
     5926static int vmdksFlush(void *pBackendData)
     5927{
     5928    LogFlowFunc(("pBackendData=%#p\n", pBackendData));
     5929    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     5930    int rc;
     5931
     5932    AssertPtr(pImage);
     5933
     5934    /* Pure dummy operation, closing takes care of everything. */
     5935    rc = VINF_SUCCESS;
     5936    LogFlowFunc(("returns %Rrc\n", rc));
     5937    return rc;
     5938}
     5939
     5940/** @copydoc VBOXHDDBACKEND::pfnSetPCHSGeometry */
     5941static int vmdksSetPCHSGeometry(void *pBackendData, PCVDGEOMETRY pPCHSGeometry)
     5942{
     5943    LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
     5944    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     5945    int rc;
     5946
     5947    AssertPtr(pImage);
     5948
     5949    if (pImage)
     5950    {
     5951        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     5952            rc = VERR_VD_IMAGE_READ_ONLY;
     5953        else
     5954            rc = VERR_NOT_SUPPORTED;
     5955    }
     5956    else
     5957        rc = VERR_VD_NOT_OPENED;
     5958
     5959    LogFlowFunc(("returns %Rrc\n", rc));
     5960    return rc;
     5961}
     5962
     5963/** @copydoc VBOXHDDBACKEND::pfnSetLCHSGeometry */
     5964static int vmdksSetLCHSGeometry(void *pBackendData, PCVDGEOMETRY pLCHSGeometry)
     5965{
     5966    LogFlowFunc(("pBackendData=%#p pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pBackendData, pLCHSGeometry, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
     5967    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     5968    int rc;
     5969
     5970    AssertPtr(pImage);
     5971
     5972    if (pImage)
     5973    {
     5974        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     5975            rc = VERR_VD_IMAGE_READ_ONLY;
     5976        else
     5977            rc = VERR_NOT_SUPPORTED;
     5978    }
     5979    else
     5980        rc = VERR_VD_NOT_OPENED;
     5981
     5982    LogFlowFunc(("returns %Rrc\n", rc));
     5983    return rc;
     5984}
     5985
     5986/** @copydoc VBOXHDDBACKEND::pfnSetOpenFlags */
     5987static int vmdksSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
     5988{
     5989    LogFlowFunc(("pBackendData=%#p\n uOpenFlags=%#x", pBackendData, uOpenFlags));
     5990    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     5991    int rc = VINF_SUCCESS;
     5992
     5993    /* Image must be opened and the new flags must be the same as before. */
     5994    if (!pImage || pImage->uOpenFlags != uOpenFlags)
     5995    {
     5996        rc = VERR_INVALID_PARAMETER;
     5997        goto out;
     5998    }
     5999
     6000out:
     6001    LogFlowFunc(("returns %Rrc\n", rc));
     6002    return rc;
     6003}
     6004
     6005/** @copydoc VBOXHDDBACKEND::pfnSetComment */
     6006static int vmdksSetComment(void *pBackendData, const char *pszComment)
     6007{
     6008    LogFlowFunc(("pBackendData=%#p pszComment=\"%s\"\n", pBackendData, pszComment));
     6009    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     6010    int rc;
     6011
     6012    AssertPtr(pImage);
     6013
     6014    if (pImage)
     6015    {
     6016        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     6017            rc = VERR_VD_IMAGE_READ_ONLY;
     6018        else
     6019            rc = VERR_NOT_SUPPORTED;
     6020    }
     6021    else
     6022        rc = VERR_VD_NOT_OPENED;
     6023
     6024    LogFlowFunc(("returns %Rrc\n", rc));
     6025    return rc;
     6026}
     6027
     6028/** @copydoc VBOXHDDBACKEND::pfnSetUuid */
     6029static int vmdksSetUuid(void *pBackendData, PCRTUUID pUuid)
     6030{
     6031    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
     6032    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     6033    int rc;
     6034
     6035    LogFlowFunc(("%RTuuid\n", pUuid));
     6036    AssertPtr(pImage);
     6037
     6038    if (pImage)
     6039    {
     6040        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     6041            rc = VERR_VD_IMAGE_READ_ONLY;
     6042        else
     6043            rc = VERR_NOT_SUPPORTED;
     6044    }
     6045    else
     6046        rc = VERR_VD_NOT_OPENED;
     6047
     6048    LogFlowFunc(("returns %Rrc\n", rc));
     6049    return rc;
     6050}
     6051
     6052/** @copydoc VBOXHDDBACKEND::pfnSetModificationUuid */
     6053static int vmdksSetModificationUuid(void *pBackendData, PCRTUUID pUuid)
     6054{
     6055    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
     6056    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     6057    int rc;
     6058
     6059    AssertPtr(pImage);
     6060
     6061    if (pImage)
     6062    {
     6063        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     6064            rc = VERR_VD_IMAGE_READ_ONLY;
     6065        else
     6066            rc = VERR_NOT_SUPPORTED;
     6067    }
     6068    else
     6069        rc = VERR_VD_NOT_OPENED;
     6070
     6071    LogFlowFunc(("returns %Rrc\n", rc));
     6072    return rc;
     6073}
     6074
     6075/** @copydoc VBOXHDDBACKEND::pfnSetParentUuid */
     6076static int vmdksSetParentUuid(void *pBackendData, PCRTUUID pUuid)
     6077{
     6078    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
     6079    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     6080    int rc;
     6081
     6082    AssertPtr(pImage);
     6083
     6084    if (pImage)
     6085    {
     6086        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     6087            rc = VERR_VD_IMAGE_READ_ONLY;
     6088        else
     6089            rc = VERR_NOT_SUPPORTED;
     6090    }
     6091    else
     6092        rc = VERR_VD_NOT_OPENED;
     6093
     6094    LogFlowFunc(("returns %Rrc\n", rc));
     6095    return rc;
     6096}
     6097
     6098/** @copydoc VBOXHDDBACKEND::pfnSetParentModificationUuid */
     6099static int vmdksSetParentModificationUuid(void *pBackendData, PCRTUUID pUuid)
     6100{
     6101    LogFlowFunc(("pBackendData=%#p Uuid=%RTuuid\n", pBackendData, pUuid));
     6102    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     6103    int rc;
     6104
     6105    AssertPtr(pImage);
     6106
     6107    if (pImage)
     6108    {
     6109        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     6110            rc = VERR_VD_IMAGE_READ_ONLY;
     6111        else
     6112            rc = VERR_NOT_SUPPORTED;
     6113    }
     6114    else
     6115        rc = VERR_VD_NOT_OPENED;
     6116
     6117    LogFlowFunc(("returns %Rrc\n", rc));
     6118    return rc;
    51976119}
    51986120
     
    67787700    return rc;
    67797701}
     7702
     7703
     7704VBOXHDDBACKEND g_VmdkStreamBackend =
     7705{
     7706    /* pszBackendName */
     7707    "VMDKstream",
     7708    /* cbSize */
     7709    sizeof(VBOXHDDBACKEND),
     7710    /* uBackendCaps */
     7711    VD_CAP_UUID | VD_CAP_CREATE_DYNAMIC | VD_CAP_FILE | VD_CAP_VFS,
     7712    /* papszFileExtensions */
     7713    s_apszVmdkFileExtensions,
     7714    /* paConfigInfo */
     7715    NULL,
     7716    /* hPlugin */
     7717    NIL_RTLDRMOD,
     7718    /* pfnCheckIfValid */
     7719    vmdksCheckIfValid,
     7720    /* pfnOpen */
     7721    vmdksOpen,
     7722    /* pfnCreate */
     7723    vmdksCreate,
     7724    /* pfnRename */
     7725    NULL,
     7726    /* pfnClose */
     7727    vmdksClose,
     7728    /* pfnRead */
     7729    vmdksRead,
     7730    /* pfnWrite */
     7731    vmdksWrite,
     7732    /* pfnFlush */
     7733    vmdksFlush,
     7734    /* pfnGetVersion */
     7735    vmdkGetVersion,
     7736    /* pfnGetSize */
     7737    vmdkGetSize,
     7738    /* pfnGetFileSize */
     7739    vmdkGetFileSize,
     7740    /* pfnGetPCHSGeometry */
     7741    vmdkGetPCHSGeometry,
     7742    /* pfnSetPCHSGeometry */
     7743    vmdksSetPCHSGeometry,
     7744    /* pfnGetLCHSGeometry */
     7745    vmdkGetLCHSGeometry,
     7746    /* pfnSetLCHSGeometry */
     7747    vmdksSetLCHSGeometry,
     7748    /* pfnGetImageFlags */
     7749    vmdkGetImageFlags,
     7750    /* pfnGetOpenFlags */
     7751    vmdkGetOpenFlags,
     7752    /* pfnSetOpenFlags */
     7753    vmdksSetOpenFlags,
     7754    /* pfnGetComment */
     7755    vmdkGetComment,
     7756    /* pfnSetComment */
     7757    vmdksSetComment,
     7758    /* pfnGetUuid */
     7759    vmdkGetUuid,
     7760    /* pfnSetUuid */
     7761    vmdksSetUuid,
     7762    /* pfnGetModificationUuid */
     7763    vmdkGetModificationUuid,
     7764    /* pfnSetModificationUuid */
     7765    vmdksSetModificationUuid,
     7766    /* pfnGetParentUuid */
     7767    vmdkGetParentUuid,
     7768    /* pfnSetParentUuid */
     7769    vmdksSetParentUuid,
     7770    /* pfnGetParentModificationUuid */
     7771    vmdkGetParentModificationUuid,
     7772    /* pfnSetParentModificationUuid */
     7773    vmdksSetParentModificationUuid,
     7774    /* pfnDump */
     7775    vmdkDump,
     7776    /* pfnGetTimeStamp */
     7777    NULL,
     7778    /* pfnGetParentTimeStamp */
     7779    NULL,
     7780    /* pfnSetParentTimeStamp */
     7781    NULL,
     7782    /* pfnGetParentFilename */
     7783    NULL,
     7784    /* pfnSetParentFilename */
     7785    NULL,
     7786    /* pfnIsAsyncIOSupported */
     7787    NULL,
     7788    /* pfnAsyncRead */
     7789    NULL,
     7790    /* pfnAsyncWrite */
     7791    NULL,
     7792    /* pfnAsyncFlush */
     7793    NULL,
     7794    /* pfnComposeLocation */
     7795    genericFileComposeLocation,
     7796    /* pfnComposeName */
     7797    genericFileComposeName,
     7798    /* pfnCompact */
     7799    NULL,
     7800    /* pfnResize */
     7801    NULL
     7802};
    67807803
    67817804
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette