/** @copydoc fuse_operations::write */ static int vboxfuseOp_write(const char *pszPath, const char *pbBuf, size_t cbBuf, off_t offFile, struct fuse_file_info *pInfo) { /* paranoia */ AssertReturn((int)cbBuf >= 0, -EINVAL); AssertReturn((unsigned)cbBuf == cbBuf, -EINVAL); AssertReturn(offFile >= 0, -EINVAL); AssertReturn((off_t)(offFile + cbBuf) >= offFile, -EINVAL); PVBOXFUSENODE pNode = (PVBOXFUSENODE)(uintptr_t)pInfo->fh; AssertPtr(pNode); switch (pNode->enmType) { case VBOXFUSETYPE_DIRECTORY: return -ENOTSUP; case VBOXFUSETYPE_FLAT_IMAGE: { PVBOXFUSEFLATIMAGE pFlatImage = (PVBOXFUSEFLATIMAGE)(uintptr_t)pInfo->fh; LogFlow(("vboxfuseOp_write: offFile=%#llx cbBuf=%#zx pszPath=\"%s\"\n", (uint64_t)offFile, cbBuf, pszPath)); vboxfuseNodeLock(&pFlatImage->Node); int rc; if ((off_t)(offFile + cbBuf) < offFile) rc = -EINVAL; else if (offFile >= pFlatImage->Node.cbPrimary) rc = 0; else if (!cbBuf) rc = 0; else { /* Adjust for EOF. */ if ((off_t)(offFile + cbBuf) >= pFlatImage->Node.cbPrimary) cbBuf = pFlatImage->Node.cbPrimary - offFile; /* * Aligned write? */ int rc2; if ( !(offFile & VBOXFUSE_MIN_SIZE_MASK_OFF) && !(cbBuf & VBOXFUSE_MIN_SIZE_MASK_OFF)) rc2 = VDWrite(pFlatImage->pDisk, offFile, pbBuf, cbBuf); else { /* * Unaligned write - lots of extra work. */ uint8_t abBlock[VBOXFUSE_MIN_SIZE]; if (((offFile + cbBuf) & VBOXFUSE_MIN_SIZE_MASK_BLK) == (offFile & VBOXFUSE_MIN_SIZE_MASK_BLK)) { /* a single partial block. */ rc2 = VDRead(pFlatImage->pDisk, offFile & VBOXFUSE_MIN_SIZE_MASK_BLK, abBlock, VBOXFUSE_MIN_SIZE); if (RT_SUCCESS(rc2)) { memcpy(&abBlock[offFile & VBOXFUSE_MIN_SIZE_MASK_OFF], pbBuf, cbBuf); /* Update the block */ rc2 = VDWrite(pFlatImage->pDisk, offFile & VBOXFUSE_MIN_SIZE_MASK_BLK, abBlock, VBOXFUSE_MIN_SIZE); } } else { /* read unaligned head. */ rc2 = VINF_SUCCESS; if (offFile & VBOXFUSE_MIN_SIZE_MASK_OFF) { rc2 = VDRead(pFlatImage->pDisk, offFile & VBOXFUSE_MIN_SIZE_MASK_BLK, abBlock, VBOXFUSE_MIN_SIZE); if (RT_SUCCESS(rc2)) { size_t cbCopy = VBOXFUSE_MIN_SIZE - (offFile & VBOXFUSE_MIN_SIZE_MASK_OFF); memcpy(&abBlock[offFile & VBOXFUSE_MIN_SIZE_MASK_OFF], pbBuf, cbCopy); pbBuf += cbCopy; offFile += cbCopy; cbBuf -= cbCopy; rc2 = VDWrite(pFlatImage->pDisk, offFile & VBOXFUSE_MIN_SIZE_MASK_BLK, abBlock, VBOXFUSE_MIN_SIZE); } } /* write the middle. */ Assert(!(offFile & VBOXFUSE_MIN_SIZE_MASK_OFF)); if (cbBuf >= VBOXFUSE_MIN_SIZE && RT_SUCCESS(rc2)) { size_t cbWrite = cbBuf & VBOXFUSE_MIN_SIZE_MASK_BLK; rc2 = VDWrite(pFlatImage->pDisk, offFile, pbBuf, cbWrite); if (RT_SUCCESS(rc2)) { pbBuf += cbWrite; offFile += cbWrite; cbBuf -= cbWrite; } } /* unaligned tail write. */ Assert(cbBuf < VBOXFUSE_MIN_SIZE); Assert(!(offFile & VBOXFUSE_MIN_SIZE_MASK_OFF)); if (cbBuf && RT_SUCCESS(rc2)) { rc2 = VDRead(pFlatImage->pDisk, offFile, abBlock, VBOXFUSE_MIN_SIZE); if (RT_SUCCESS(rc2)) { memcpy(&abBlock[0], pbBuf, cbBuf); rc2 = VDWrite(pFlatImage->pDisk, offFile, abBlock, VBOXFUSE_MIN_SIZE); } } } } /* convert the return code */ if (RT_SUCCESS(rc2)) rc = cbBuf; else rc = -RTErrConvertToErrno(rc2); } vboxfuseNodeUnlock(&pFlatImage->Node); return rc; } case VBOXFUSETYPE_CONTROL_PIPE: return -ENOTSUP; default: AssertMsgFailed(("%s\n", pszPath)); return -EDOOFUS; } }
static int tstVDSnapWrite(PVBOXHDD pVD, PVDDISKSEG paDiskSegments, uint32_t cDiskSegments, uint64_t cbDisk, bool fInit) { int rc = VINF_SUCCESS; for (uint32_t i = 0; i < cDiskSegments; i++) { if (fInit || paDiskSegments[i].pbDataDiff) { size_t cbWrite = paDiskSegments[i].cbSeg; uint64_t off = paDiskSegments[i].off; uint8_t *pbData = fInit ? paDiskSegments[i].pbData : paDiskSegments[i].pbDataDiff; if (pbData) { rc = VDWrite(pVD, off, pbData, cbWrite); if (RT_FAILURE(rc)) return rc; } } } return rc; }
/** * VD write helper taking care of unaligned accesses. * * @return VBox status code. * @param pDisk VD disk container. * @param off Offset to start writing to. * @param pvBuf Pointer to the buffer to read from. * @param cbWrite Amount of bytes to write. */ static int vdWriteHelper(PVBOXHDD pDisk, uint64_t off, const void *pvBuf, size_t cbWrite) { int rc = VINF_SUCCESS; /* Take shortcut if possible. */ if ( off % 512 == 0 && cbWrite % 512 == 0) rc = VDWrite(pDisk, off, pvBuf, cbWrite); else { uint8_t *pbBuf = (uint8_t *)pvBuf; uint8_t abBuf[512]; /* Unaligned access, make it aligned. */ if (off % 512 != 0) { uint64_t offAligned = off & ~(uint64_t)(512 - 1); size_t cbToCopy = 512 - (off - offAligned); rc = VDRead(pDisk, offAligned, abBuf, 512); if (RT_SUCCESS(rc)) { memcpy(&abBuf[off - offAligned], pbBuf, cbToCopy); rc = VDWrite(pDisk, offAligned, abBuf, 512); pbBuf += cbToCopy; off += cbToCopy; cbWrite -= cbToCopy; } } if ( RT_SUCCESS(rc) && (cbWrite & ~(uint64_t)(512 - 1))) { size_t cbWriteAligned = cbWrite & ~(uint64_t)(512 - 1); Assert(!(off % 512)); rc = VDWrite(pDisk, off, pbBuf, cbWriteAligned); if (RT_SUCCESS(rc)) { pbBuf += cbWriteAligned; off += cbWriteAligned; cbWrite -= cbWriteAligned; } } if ( RT_SUCCESS(rc) && cbWrite) { Assert(cbWrite < 512); Assert(!(off % 512)); rc = VDRead(pDisk, off, abBuf, 512); if (RT_SUCCESS(rc)) { memcpy(abBuf, pbBuf, cbWrite); rc = VDWrite(pDisk, off, abBuf, 512); } } } return rc; }