Ejemplo n.º 1
1
/** @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;
}
Ejemplo n.º 3
0
/**
 * 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;
}