Example #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;
    }
}
Example #2
0
/**
 * VD read helper taking care of unaligned accesses.
 *
 * @return  VBox status code.
 * @param   pDisk    VD disk container.
 * @param   off      Offset to start reading from.
 * @param   pvBuf    Pointer to the buffer to read into.
 * @param   cbRead   Amount of bytes to read.
 */
static int vdReadHelper(PVBOXHDD pDisk, uint64_t off, void *pvBuf, size_t cbRead)
{
    int rc = VINF_SUCCESS;

    /* Take shortcut if possible. */
    if (   off % 512 == 0
        && cbRead % 512 == 0)
        rc = VDRead(pDisk, off, pvBuf, cbRead);
    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(pbBuf, &abBuf[off - offAligned], cbToCopy);
                pbBuf  += cbToCopy;
                off    += cbToCopy;
                cbRead -= cbToCopy;
            }
        }

        if (   RT_SUCCESS(rc)
            && (cbRead & ~(uint64_t)(512 - 1)))
        {
            size_t cbReadAligned = cbRead & ~(uint64_t)(512 - 1);

            Assert(!(off % 512));
            rc = VDRead(pDisk, off, pbBuf, cbReadAligned);
            if (RT_SUCCESS(rc))
            {
                pbBuf  += cbReadAligned;
                off    += cbReadAligned;
                cbRead -= cbReadAligned;
            }
        }

        if (   RT_SUCCESS(rc)
            && cbRead)
        {
            Assert(cbRead < 512);
            Assert(!(off % 512));

            rc = VDRead(pDisk, off, abBuf, 512);
            if (RT_SUCCESS(rc))
                memcpy(pbBuf, abBuf, cbRead);
        }
    }

    return rc;
}
int main(int argc, char *argv[])
{
    int rc;

    RTR3InitExe(argc, &argv, 0);

    if (argc != 3)
    {
        RTPrintf("Usage: ./tstVDCopy <hdd1> <hdd2>\n");
        return 1;
    }

    RTPrintf("tstVDCopy: TESTING...\n");

    PVBOXHDD         pVD1 = NULL;
    PVBOXHDD         pVD2 = NULL;
    PVDINTERFACE     pVDIfs = NULL;
    VDINTERFACEERROR VDIfError;
    char *pszVD1 = NULL;
    char *pszVD2 = NULL;
    char *pbBuf1 = NULL;
    char *pbBuf2 = NULL;
    VDTYPE enmTypeVD1 = VDTYPE_INVALID;
    VDTYPE enmTypeVD2 = VDTYPE_INVALID;

#define CHECK(str) \
    do \
    { \
        if (RT_FAILURE(rc)) \
        { \
            RTPrintf("%s rc=%Rrc\n", str, rc); \
            if (pVD1) \
                VDCloseAll(pVD1); \
            if (pVD2) \
                VDCloseAll(pVD2); \
            return rc; \
        } \
    } while (0)

    pbBuf1 = (char *)RTMemAllocZ(VD_MERGE_BUFFER_SIZE);
    pbBuf2 = (char *)RTMemAllocZ(VD_MERGE_BUFFER_SIZE);

    /* Create error interface. */
    VDIfError.pfnError = tstVDError;

    rc = VDInterfaceAdd(&VDIfError.Core, "tstVD_Error", VDINTERFACETYPE_ERROR,
                        NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
    AssertRC(rc);

    rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
                     argv[1], &pszVD1, &enmTypeVD1);
    CHECK("VDGetFormat() hdd1");

    rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
                     argv[2], &pszVD2, &enmTypeVD2);
    CHECK("VDGetFormat() hdd2");

    rc = VDCreate(pVDIfs, VDTYPE_HDD, &pVD1);
    CHECK("VDCreate() hdd1");

    rc = VDCreate(pVDIfs, VDTYPE_HDD, &pVD2);
    CHECK("VDCreate() hdd1");

    rc = VDOpen(pVD1, pszVD1, argv[1], VD_OPEN_FLAGS_NORMAL, NULL);
    CHECK("VDOpen() hdd1");

    rc = VDOpen(pVD2, pszVD2, argv[2], VD_OPEN_FLAGS_NORMAL, NULL);
    CHECK("VDOpen() hdd2");

    uint64_t cbSize1 = 0;
    uint64_t cbSize2 = 0;

    cbSize1 = VDGetSize(pVD1, 0);
    Assert(cbSize1 != 0);
    cbSize2 = VDGetSize(pVD1, 0);
    Assert(cbSize1 != 0);

    if (cbSize1 == cbSize2)
    {
        uint64_t uOffCurr = 0;

        /* Compare block by block. */
        while (uOffCurr < cbSize1)
        {
            size_t cbRead = RT_MIN((cbSize1 - uOffCurr), VD_MERGE_BUFFER_SIZE);

            rc = VDRead(pVD1, uOffCurr, pbBuf1, cbRead);
            CHECK("VDRead() hdd1");

            rc = VDRead(pVD2, uOffCurr, pbBuf2, cbRead);
            CHECK("VDRead() hdd2");

            if (memcmp(pbBuf1, pbBuf2, cbRead))
            {
                RTPrintf("tstVDCopy: Images differ uOffCurr=%llu\n", uOffCurr);
                /* Do byte by byte comparison. */
                for (size_t i = 0; i < cbRead; i++)
                {
                    if (pbBuf1[i] != pbBuf2[i])
                    {
                        RTPrintf("tstVDCopy: First different byte is at offset %llu\n", uOffCurr + i);
                        break;
                    }
                }
                break;
            }

            uOffCurr += cbRead;
        }
    }
    else
        RTPrintf("tstVDCopy: Images have different size hdd1=%llu hdd2=%llu\n", cbSize1, cbSize2);

    VDClose(pVD1, false);
    CHECK("VDClose() hdd1");

    VDClose(pVD2, false);
    CHECK("VDClose() hdd2");

    VDDestroy(pVD1);
    VDDestroy(pVD2);
    RTMemFree(pbBuf1);
    RTMemFree(pbBuf2);
#undef CHECK

    rc = VDShutdown();
    if (RT_FAILURE(rc))
    {
        RTPrintf("tstVDCopy: unloading backends failed! rc=%Rrc\n", rc);
        g_cErrors++;
    }
    /*
     * Summary
     */
    if (!g_cErrors)
        RTPrintf("tstVDCopy: SUCCESS\n");
    else
        RTPrintf("tstVDCopy: FAILURE - %d errors\n", g_cErrors);

    return !!g_cErrors;
}
static int tstVDSnapReadVerify(PVBOXHDD pVD, PVDDISKSEG paDiskSegments, uint32_t cDiskSegments, uint64_t cbDisk)
{
    int rc = VINF_SUCCESS;
    uint8_t *pbBuf = (uint8_t *)RTMemAlloc(_1M);

    for (uint32_t i = 0; i < cDiskSegments; i++)
    {
        size_t cbRead  = paDiskSegments[i].cbSeg;
        uint64_t off   = paDiskSegments[i].off;
        uint8_t *pbCmp = paDiskSegments[i].pbData;

        Assert(!paDiskSegments[i].pbDataDiff);

        while (cbRead)
        {
            size_t cbToRead = RT_MIN(cbRead, _1M);

            rc = VDRead(pVD, off, pbBuf, cbToRead);
            if (RT_FAILURE(rc))
                return rc;

            if (pbCmp)
            {
                if (memcmp(pbCmp, pbBuf, cbToRead))
                {
                    for (unsigned iCmp = 0; iCmp < cbToRead; iCmp++)
                    {
                        if (pbCmp[iCmp] != pbBuf[iCmp])
                        {
                            RTPrintf("Unexpected data at %llu expected %#x got %#x\n", off+iCmp, pbCmp[iCmp], pbBuf[iCmp]);
                            break;
                        }
                    }
                    return VERR_INTERNAL_ERROR;
                }
            }
            else
            {
                /* Verify that the block is 0 */
                for (unsigned iCmp = 0; iCmp < cbToRead; iCmp++)
                {
                    if (pbBuf[iCmp] != 0)
                    {
                        RTPrintf("Zero block contains data at %llu\n", off+iCmp);
                        return VERR_INTERNAL_ERROR;
                    }
                }
            }

            cbRead -= cbToRead;
            off    += cbToRead;

            if (pbCmp)
                pbCmp  += cbToRead;
        }
    }

    RTMemFree(pbBuf);

    return rc;
}