Example #1
0
/**
 * Internal. Flush image data to disk.
 */
static int parallelsFlushImage(PPARALLELSIMAGE pImage)
{
    int rc = VINF_SUCCESS;

    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
        return VINF_SUCCESS;

    if (   !(pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
        && (pImage->fAllocationBitmapChanged))
    {
        pImage->fAllocationBitmapChanged = false;
        /* Write the allocation bitmap to the file. */
        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
                                    sizeof(ParallelsHeader), pImage->pAllocationBitmap,
                                    pImage->cAllocationBitmapEntries * sizeof(uint32_t),
                                    NULL);
        if (RT_FAILURE(rc))
            return rc;
    }

    /* Flush file. */
    rc = vdIfIoIntFileFlushSync(pImage->pIfIo, pImage->pStorage);

    LogFlowFunc(("returns %Rrc\n", rc));
    return rc;
}
Example #2
0
/**
 * Internal. Free all allocated space for representing an image except pImage,
 * and optionally delete the image from disk.
 */
static int rawFreeImage(PRAWIMAGE pImage, bool fDelete)
{
    int rc = VINF_SUCCESS;

    /* Freeing a never allocated image (e.g. because the open failed) is
     * not signalled as an error. After all nothing bad happens. */
    if (pImage)
    {
        if (pImage->pStorage)
        {
            /* No point updating the file that is deleted anyway. */
            if (!fDelete)
            {
                /* For newly created images in sequential mode fill it to
                 * the nominal size. */
                if (   pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
                        && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
                        && pImage->fCreate)
                {
                    /* Fill rest of image with zeroes, a must for sequential
                     * images to reach the nominal size. */
                    uint64_t uOff;
                    void *pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
                    if (RT_LIKELY(pvBuf))
                    {
                        uOff = pImage->offAccess;
                        /* Write data to all image blocks. */
                        while (uOff < pImage->cbSize)
                        {
                            unsigned cbChunk = (unsigned)RT_MIN(pImage->cbSize - uOff,
                                                                RAW_FILL_SIZE);

                            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
                                                        uOff, pvBuf, cbChunk);
                            if (RT_FAILURE(rc))
                                break;

                            uOff += cbChunk;
                        }

                        RTMemTmpFree(pvBuf);
                    }
                    else
                        rc = VERR_NO_MEMORY;
                }
                rawFlushImage(pImage);
            }

            rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
            pImage->pStorage = NULL;
        }

        if (fDelete && pImage->pszFilename)
            vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
    }

    LogFlowFunc(("returns %Rrc\n", rc));
    return rc;
}
Example #3
0
/** @copydoc VBOXHDDBACKEND::pfnWrite */
static int rawWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
                    size_t cbToWrite, size_t *pcbWriteProcess,
                    size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
{
    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n", pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
    PRAWIMAGE pImage = (PRAWIMAGE)pBackendData;
    int rc;

    AssertPtr(pImage);
    Assert(uOffset % 512 == 0);
    Assert(cbToWrite % 512 == 0);

    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
    {
        rc = VERR_VD_IMAGE_READ_ONLY;
        goto out;
    }

    if (   uOffset + cbToWrite > pImage->cbSize
        || cbToWrite == 0)
    {
        rc = VERR_INVALID_PARAMETER;
        goto out;
    }

    /* For sequential access do not allow to go back. */
    if (   pImage->uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL
        && uOffset < pImage->offAccess)
    {
        rc = VERR_INVALID_PARAMETER;
        goto out;
    }

    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf,
                                cbToWrite, NULL);
    pImage->offAccess = uOffset + cbToWrite;
    if (pcbWriteProcess)
        *pcbWriteProcess = cbToWrite;

out:
    LogFlowFunc(("returns %Rrc\n", rc));
    return rc;
}
Example #4
0
/**
 * Internal: Create a raw image.
 */
static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize,
                          unsigned uImageFlags, const char *pszComment,
                          PCVDGEOMETRY pPCHSGeometry,
                          PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
                          PFNVDPROGRESS pfnProgress, void *pvUser,
                          unsigned uPercentStart, unsigned uPercentSpan)
{
    int rc;
    RTFOFF cbFree = 0;
    uint64_t uOff;
    void *pvBuf = NULL;
    int32_t fOpen;

    uImageFlags |= VD_IMAGE_FLAGS_FIXED;

    pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;

    pImage->uImageFlags = uImageFlags;
    pImage->fCreate = true;
    pImage->PCHSGeometry = *pPCHSGeometry;
    pImage->LCHSGeometry = *pLCHSGeometry;

    pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
    pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
    AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);

    if (uImageFlags & VD_IMAGE_FLAGS_DIFF)
    {
        rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename);
        goto out;
    }

    /* Create image file. */
    fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
    if (uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)
        fOpen &= ~RTFILE_O_READ;
    rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
    if (RT_FAILURE(rc))
    {
        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename);
        goto out;
    }

    if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL))
    {
        /* Check the free space on the disk and leave early if there is not
         * sufficient space available. */
        rc = vdIfIoIntFileGetFreeSpace(pImage->pIfIo, pImage->pszFilename, &cbFree);
        if (RT_SUCCESS(rc) /* ignore errors */ && ((uint64_t)cbFree < cbSize))
        {
            rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename);
            goto out;
        }

        /* Allocate & commit whole file if fixed image, it must be more
         * effective than expanding file by write operations. */
        rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbSize);
        if (RT_FAILURE(rc))
        {
            rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: setting image size failed for '%s'"), pImage->pszFilename);
            goto out;
        }

        /* Fill image with zeroes. We do this for every fixed-size image since
         * on some systems (for example Windows Vista), it takes ages to write
         * a block near the end of a sparse file and the guest could complain
         * about an ATA timeout. */
        pvBuf = RTMemTmpAllocZ(RAW_FILL_SIZE);
        if (!pvBuf)
        {
            rc = VERR_NO_MEMORY;
            goto out;
        }

        uOff = 0;
        /* Write data to all image blocks. */
        while (uOff < cbSize)
        {
            unsigned cbChunk = (unsigned)RT_MIN(cbSize, RAW_FILL_SIZE);

            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOff,
                                        pvBuf, cbChunk, NULL);
            if (RT_FAILURE(rc))
            {
                rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: writing block failed for '%s'"), pImage->pszFilename);
                goto out;
            }

            uOff += cbChunk;

            if (pfnProgress)
            {
                rc = pfnProgress(pvUser,
                                 uPercentStart + uOff * uPercentSpan * 98 / (cbSize * 100));
                if (RT_FAILURE(rc))
                    goto out;
            }
        }
    }

    if (RT_SUCCESS(rc) && pfnProgress)
        pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);

    pImage->cbSize = cbSize;

    rc = rawFlushImage(pImage);

out:
    if (pvBuf)
        RTMemTmpFree(pvBuf);

    if (RT_SUCCESS(rc) && pfnProgress)
        pfnProgress(pvUser, uPercentStart + uPercentSpan);

    if (RT_FAILURE(rc))
        rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
    return rc;
}
Example #5
0
/** @copydoc VBOXHDDBACKEND::pfnWrite */
static int parallelsWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
                          size_t cbToWrite, size_t *pcbWriteProcess,
                          size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
{
    LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbToWrite=%zu pcbWriteProcess=%#p\n",
                 pBackendData, uOffset, pvBuf, cbToWrite, pcbWriteProcess));
    PPARALLELSIMAGE pImage = (PPARALLELSIMAGE)pBackendData;
    int rc = VINF_SUCCESS;

    AssertPtr(pImage);
    Assert(uOffset % 512 == 0);
    Assert(cbToWrite % 512 == 0);

    if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
        rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffset,
                                    pvBuf, cbToWrite, NULL);
    else
    {
        uint64_t uSector;
        uint64_t uOffsetInFile;
        uint32_t iIndexInAllocationTable;

        /* Calculate offset in the real file. */
        uSector = uOffset / 512;
        /* One chunk in the file is always one track big. */
        iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
        uSector = uSector % pImage->PCHSGeometry.cSectors;

        Assert(iIndexInAllocationTable < pImage->cAllocationBitmapEntries);

        cbToWrite = RT_MIN(cbToWrite, (pImage->PCHSGeometry.cSectors - uSector)*512);

        LogFlowFunc(("AllocationBitmap[%u]=%u uSector=%u cbToWrite=%zu cAllocationBitmapEntries=%u\n",
                     iIndexInAllocationTable, pImage->pAllocationBitmap[iIndexInAllocationTable],
                     uSector, cbToWrite, pImage->cAllocationBitmapEntries));

        if (pImage->pAllocationBitmap[iIndexInAllocationTable] == 0)
        {
            if (   cbToWrite == pImage->PCHSGeometry.cSectors * 512
                && !(fWrite & VD_WRITE_NO_ALLOC))
            {
                /* Stay on the safe side. Do not run the risk of confusing the higher
                 * level, as that can be pretty lethal to image consistency. */
                *pcbPreRead = 0;
                *pcbPostRead = 0;

                /* Allocate new chunk in the file. */
                AssertMsg(pImage->cbFileCurrent % 512 == 0, ("File size is not a multiple of 512\n"));
                pImage->pAllocationBitmap[iIndexInAllocationTable] = (uint32_t)(pImage->cbFileCurrent / 512);
                pImage->cbFileCurrent += pImage->PCHSGeometry.cSectors * 512;
                pImage->fAllocationBitmapChanged = true;

                uOffsetInFile = (uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] * 512;

                LogFlowFunc(("uOffsetInFile=%llu\n", uOffsetInFile));

                /*
                 * Write the new block at the current end of the file.
                 */
                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
                                            uOffsetInFile, pvBuf, cbToWrite, NULL);
            }
            else
            {
                /* Trying to do a partial write to an unallocated cluster. Don't do
                 * anything except letting the upper layer know what to do. */
                *pcbPreRead  = uSector * 512;
                *pcbPostRead = (pImage->PCHSGeometry.cSectors * 512) - cbToWrite - *pcbPreRead;
                rc = VERR_VD_BLOCK_FREE;
            }
        }
        else
        {
            uOffsetInFile = ((uint64_t)pImage->pAllocationBitmap[iIndexInAllocationTable] + uSector) * 512;

            LogFlowFunc(("uOffsetInFile=%llu\n", uOffsetInFile));
            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffsetInFile,
                                        pvBuf, cbToWrite, NULL);
        }
    }

    if (pcbWriteProcess)
        *pcbWriteProcess = cbToWrite;

out:
    LogFlowFunc(("returns %Rrc\n", rc));
    return rc;
}
Example #6
0
/**
 * Internal: Create a parallels image.
 */
static int parallelsCreateImage(PPARALLELSIMAGE pImage, uint64_t cbSize,
                                unsigned uImageFlags, const char *pszComment,
                                PCVDGEOMETRY pPCHSGeometry,
                                PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags,
                                PFNVDPROGRESS pfnProgress, void *pvUser,
                                unsigned uPercentStart, unsigned uPercentSpan)
{
    int rc = VINF_SUCCESS;
    int32_t fOpen;

    if (uImageFlags & VD_IMAGE_FLAGS_FIXED)
    {
        rc = vdIfError(pImage->pIfError, VERR_VD_INVALID_TYPE, RT_SRC_POS, N_("Parallels: cannot create fixed image '%s'. Create a raw image"), pImage->pszFilename);
        goto out;
    }

    pImage->uOpenFlags   = uOpenFlags & ~VD_OPEN_FLAGS_READONLY;
    pImage->uImageFlags  = uImageFlags;
    pImage->PCHSGeometry = *pPCHSGeometry;
    pImage->LCHSGeometry = *pLCHSGeometry;

    if (!pImage->PCHSGeometry.cCylinders)
    {
        /* Set defaults. */
        pImage->PCHSGeometry.cSectors   = 63;
        pImage->PCHSGeometry.cHeads     = 16;
        pImage->PCHSGeometry.cCylinders = pImage->cbSize / (512 * pImage->PCHSGeometry.cSectors * pImage->PCHSGeometry.cHeads);
    }

    pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk);
    pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage);
    AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER);

    /* Create image file. */
    fOpen = VDOpenFlagsToFileOpenFlags(pImage->uOpenFlags, true /* fCreate */);
    rc = vdIfIoIntFileOpen(pImage->pIfIo, pImage->pszFilename, fOpen, &pImage->pStorage);
    if (RT_FAILURE(rc))
    {
        rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Parallels: cannot create image '%s'"), pImage->pszFilename);
        goto out;
    }

    if (RT_SUCCESS(rc) && pfnProgress)
        pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100);

    /* Setup image state. */
    pImage->cbSize                   = cbSize;
    pImage->cAllocationBitmapEntries = cbSize / 512 / pImage->PCHSGeometry.cSectors;
    if (pImage->cAllocationBitmapEntries * pImage->PCHSGeometry.cSectors * 512 < cbSize)
        pImage->cAllocationBitmapEntries++;
    pImage->fAllocationBitmapChanged = true;
    pImage->cbFileCurrent            = sizeof(ParallelsHeader) + pImage->cAllocationBitmapEntries * sizeof(uint32_t);
    /* Round to next sector boundary. */
    pImage->cbFileCurrent           += 512 - pImage->cbFileCurrent % 512;
    Assert(!(pImage->cbFileCurrent % 512));
    pImage->pAllocationBitmap        = (uint32_t *)RTMemAllocZ(pImage->cAllocationBitmapEntries * sizeof(uint32_t));
    if (!pImage->pAllocationBitmap)
        rc = VERR_NO_MEMORY;

    if (RT_SUCCESS(rc))
    {
        ParallelsHeader Header;

        memcpy(Header.HeaderIdentifier, PARALLELS_HEADER_MAGIC, sizeof(Header.HeaderIdentifier));
        Header.uVersion                   = RT_H2LE_U32(PARALLELS_DISK_VERSION);
        Header.cHeads                     = RT_H2LE_U32(pImage->PCHSGeometry.cHeads);
        Header.cCylinders                 = RT_H2LE_U32(pImage->PCHSGeometry.cCylinders);
        Header.cSectorsPerTrack           = RT_H2LE_U32(pImage->PCHSGeometry.cSectors);
        Header.cEntriesInAllocationBitmap = RT_H2LE_U32(pImage->cAllocationBitmapEntries);
        Header.cSectors                   = RT_H2LE_U32(pImage->cbSize / 512);
        memset(Header.Padding, 0, sizeof(Header.Padding));

        /* Write header and allocation bitmap. */
        rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, pImage->cbFileCurrent);
        if (RT_SUCCESS(rc))
            rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0,
                                        &Header, sizeof(Header), NULL);
        if (RT_SUCCESS(rc))
            rc = parallelsFlushImage(pImage); /* Writes the allocation bitmap. */
    }

out:
    if (RT_SUCCESS(rc) && pfnProgress)
        pfnProgress(pvUser, uPercentStart + uPercentSpan);

    if (RT_FAILURE(rc))
        parallelsFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
    return rc;
}