/** * 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; }
/** @copydoc VBOXHDDBACKEND::pfnFlush */ static int rawFlush(void *pBackendData) { LogFlowFunc(("pBackendData=%#p\n", pBackendData)); PRAWIMAGE pImage = (PRAWIMAGE)pBackendData; int rc; rc = rawFlushImage(pImage); LogFlowFunc(("returns %Rrc\n", rc)); return rc; }
/** * 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; 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 = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pImage->pStorage, cbSize, 0 /* fFlags */, pfnProgress, pvUser, uPercentStart, uPercentSpan); } if (RT_SUCCESS(rc) && pfnProgress) pfnProgress(pvUser, uPercentStart + uPercentSpan * 98 / 100); pImage->cbSize = cbSize; rc = rawFlushImage(pImage); out: if (RT_SUCCESS(rc) && pfnProgress) pfnProgress(pvUser, uPercentStart + uPercentSpan); if (RT_FAILURE(rc)) rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS); return rc; }
/** * 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; }
/** * Internal: Create a raw image. */ static int rawCreateImage(PRAWIMAGE pImage, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCVDGEOMETRY pPCHSGeometry, PCVDGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PVDINTERFACEPROGRESS pIfProgress, unsigned uPercentStart, unsigned uPercentSpan) { RT_NOREF1(pszComment); int rc = VINF_SUCCESS; pImage->fCreate = true; pImage->uOpenFlags = uOpenFlags & ~VD_OPEN_FLAGS_READONLY; pImage->uImageFlags = uImageFlags | VD_IMAGE_FLAGS_FIXED; pImage->PCHSGeometry = *pPCHSGeometry; pImage->LCHSGeometry = *pLCHSGeometry; pImage->pIfError = VDIfErrorGet(pImage->pVDIfsDisk); pImage->pIfIo = VDIfIoIntGet(pImage->pVDIfsImage); AssertPtrReturn(pImage->pIfIo, VERR_INVALID_PARAMETER); if (!(pImage->uImageFlags & VD_IMAGE_FLAGS_DIFF)) { /* Create image file. */ uint32_t 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_SUCCESS(rc)) { if (!(uOpenFlags & VD_OPEN_FLAGS_SEQUENTIAL)) { RTFOFF cbFree = 0; /* 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_FAILURE(rc) /* ignore errors */ || ((uint64_t)cbFree >= cbSize)) { rc = vdIfIoIntFileSetAllocationSize(pImage->pIfIo, pImage->pStorage, cbSize, 0 /* fFlags */, pIfProgress, uPercentStart, uPercentSpan); if (RT_SUCCESS(rc)) { vdIfProgress(pIfProgress, uPercentStart + uPercentSpan * 98 / 100); pImage->cbSize = cbSize; rc = rawFlushImage(pImage); } } else rc = vdIfError(pImage->pIfError, VERR_DISK_FULL, RT_SRC_POS, N_("Raw: disk would overflow creating image '%s'"), pImage->pszFilename); } } else rc = vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("Raw: cannot create image '%s'"), pImage->pszFilename); } else rc = vdIfError(pImage->pIfError, VERR_VD_RAW_INVALID_TYPE, RT_SRC_POS, N_("Raw: cannot create diff image '%s'"), pImage->pszFilename); if (RT_SUCCESS(rc)) vdIfProgress(pIfProgress, uPercentStart + uPercentSpan); if (RT_FAILURE(rc)) rawFreeImage(pImage, rc != VERR_ALREADY_EXISTS); return rc; }