VirtualBox

Changeset 74822 in vbox for trunk


Ignore:
Timestamp:
Oct 12, 2018 6:40:09 PM (6 years ago)
Author:
vboxsync
Message:

Main: bugref:9152 Implement the convertToStream API

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/manual/en_US/man_VBoxManage-mediumio.xml

    r73276 r74822  
    5656      <arg>--offset=<replaceable>byte-offset</replaceable></arg>
    5757      <arg>--size=<replaceable>bytes</replaceable></arg>
     58      <arg>--output=<replaceable>-|filename</replaceable></arg>
     59    </cmdsynopsis>
     60    <cmdsynopsis id="synopsis-vboxmanage-mediumio-stream">
     61      <command>VBoxManage mediumio</command>
     62      <group choice="req">
     63        <arg>--disk=<replaceable>uuid|filename</replaceable></arg>
     64        <arg>--dvd=<replaceable>uuid|filename</replaceable></arg>
     65        <arg>--floppy=<replaceable>uuid|filename</replaceable></arg>
     66      </group>
     67      <arg>--password-file<replaceable>-|filename</replaceable></arg>
     68      <arg choice="plain">stream</arg>
     69      <arg>--format=<replaceable>image-format</replaceable></arg>
     70      <arg>--variant=<replaceable>image-variant</replaceable></arg>
    5871      <arg>--output=<replaceable>-|filename</replaceable></arg>
    5972    </cmdsynopsis>
     
    126139    </refsect2>
    127140
     141    <refsect2 id="vboxmanage-mediumio-stream">
     142      <title>mediumio stream</title>
     143      <remark role="help-copy-synopsis"/>
     144      <para>
     145        Converts the medium to a streamable format and dumps it to the given output.
     146      </para>
     147      <variablelist>
     148        <varlistentry>
     149          <term><option>--format</option></term><listitem><para>The format of the destination image.</para></listitem>
     150        </varlistentry>
     151        <varlistentry>
     152          <term><option>--variant</option></term><listitem><para>The medium variant for the destination.</para></listitem>
     153        </varlistentry>
     154        <varlistentry>
     155          <term><option>--output</option></term>
     156          <listitem><para>The output filename.  As usual <option>-</option> is take to mean stdout.</para></listitem>
     157        </varlistentry>
     158      </variablelist>
     159    </refsect2>
     160
    128161  </refsect1>
    129162
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp

    r74354 r74822  
    23732373}
    23742374
     2375/**
     2376 * mediumio stream
     2377 */
     2378static RTEXITCODE handleMediumIOStream(HandlerArg *a, int iFirst, PMEDIUMIOCOMMONOPT pCommonOpts)
     2379{
     2380    /*
     2381     * Parse the options.
     2382     */
     2383    static const RTGETOPTDEF s_aOptions[] =
     2384    {
     2385        MEDIUMIOCOMMONOPT_DEFS(),
     2386        { "--output",   'O', RTGETOPT_REQ_STRING },
     2387        { "--format",   'F', RTGETOPT_REQ_STRING },
     2388        { "--variant",  'v', RTGETOPT_REQ_STRING }
     2389    };
     2390    const char *pszOutput = NULL;
     2391    MediumVariant_T enmMediumVariant = MediumVariant_Standard;
     2392    Bstr strFormat;
     2393
     2394    RTGETOPTSTATE GetState;
     2395    int rc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
     2396    AssertRC(rc);
     2397    RTGETOPTUNION ValueUnion;
     2398    while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
     2399    {
     2400        switch (rc)
     2401        {
     2402            MEDIUMIOCOMMONOPT_CASES(pCommonOpts);
     2403
     2404            case 'O':
     2405                pszOutput = ValueUnion.psz;
     2406                break;
     2407            case 'F':
     2408                strFormat = ValueUnion.psz;
     2409                break;
     2410            case 'v':   // --variant
     2411            {
     2412                int vrc = parseMediumVariant(ValueUnion.psz, &enmMediumVariant);
     2413                if (RT_FAILURE(vrc))
     2414                    return errorArgument("Invalid medium variant '%s'", ValueUnion.psz);
     2415                break;
     2416            }
     2417
     2418            default:
     2419                return errorGetOpt(rc, &ValueUnion);
     2420        }
     2421    }
     2422
     2423    /*
     2424     * Open the medium for I/O.
     2425     */
     2426    ComPtr<IMediumIO>   ptrMediumIO;
     2427    uint64_t            cbMedium;
     2428    RTEXITCODE rcExit = mediumIOOpenMediumForIO(a, pCommonOpts, false /*fWritable*/, ptrMediumIO, &cbMedium);
     2429    if (rcExit == RTEXITCODE_SUCCESS)
     2430    {
     2431        /*
     2432         * Do we have an output file or do we write to stdout?
     2433         */
     2434        PRTSTREAM pOut = NULL;
     2435        if (pszOutput && (pszOutput[0] != '-' || pszOutput[1] != '\0'))
     2436        {
     2437            int vrc = RTStrmOpen(pszOutput, "wb", &pOut);
     2438            if (RT_FAILURE(vrc))
     2439                rcExit = RTMsgErrorExitFailure("Error opening '%s' for writing: %Rrc", pszOutput, vrc);
     2440        }
     2441        else
     2442        {
     2443            pOut = g_pStdOut;
     2444            RTStrmSetMode(pOut, true, -1);
     2445        }
     2446
     2447        if (rcExit == RTEXITCODE_SUCCESS)
     2448        {
     2449            ComPtr<IDataStream> ptrDataStream;
     2450            ComPtr<IProgress> ptrProgress;
     2451
     2452            com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
     2453
     2454            for (ULONG i = 0; i < l_variants.size(); ++i)
     2455            {
     2456                ULONG temp = enmMediumVariant;
     2457                temp &= 1<<i;
     2458                l_variants [i] = (MediumVariant_T)temp;
     2459            }
     2460
     2461            HRESULT hrc = ptrMediumIO->ConvertToStream(strFormat.raw(), ComSafeArrayAsInParam(l_variants), 10 * _1M, ptrDataStream.asOutParam(), ptrProgress.asOutParam());
     2462            if (hrc == S_OK)
     2463            {
     2464                /* Read until we reached the end of the stream. */
     2465                for (;;)
     2466                {
     2467                    SafeArray<BYTE> SafeArrayBuf;
     2468
     2469                    hrc = ptrDataStream->Read(_64K, 0 /*Infinite wait*/, ComSafeArrayAsOutParam(SafeArrayBuf));
     2470                    if (   FAILED(hrc)
     2471                        || SafeArrayBuf.size() == 0)
     2472                        break;
     2473
     2474                    /* Output the data. */
     2475                    size_t const cbReturned = SafeArrayBuf.size();
     2476                    if (cbReturned)
     2477                    {
     2478                        BYTE const *pbBuf = SafeArrayBuf.raw();
     2479                        int vrc = VINF_SUCCESS;
     2480                        vrc = RTStrmWrite(pOut, pbBuf, cbReturned);
     2481                        if (RT_FAILURE(vrc))
     2482                        {
     2483                            rcExit = RTMsgErrorExitFailure("Error writing to '%s': %Rrc", pszOutput, vrc);
     2484                            break;
     2485                        }
     2486                    }
     2487
     2488                    /** @todo: Check progress. */
     2489                }
     2490            }
     2491            else
     2492            {
     2493                com::GlueHandleComError(ptrMediumIO, "ConvertToStream()", hrc, __FILE__, __LINE__);
     2494                rcExit = RTEXITCODE_FAILURE;
     2495            }
     2496
     2497            /*
     2498             * Close output.
     2499             */
     2500            if (pOut != g_pStdOut)
     2501            {
     2502                int vrc = RTStrmClose(pOut);
     2503                if (RT_FAILURE(vrc))
     2504                    rcExit = RTMsgErrorExitFailure("Error closing '%s': %Rrc", pszOutput, vrc);
     2505            }
     2506            else
     2507                RTStrmSetMode(pOut, false, -1);
     2508        }
     2509    }
     2510    return rcExit;
     2511}
     2512
    23752513
    23762514RTEXITCODE handleMediumIO(HandlerArg *a)
     
    23852523        { "formatfat",  1000, RTGETOPT_REQ_NOTHING },
    23862524        { "cat",        1001, RTGETOPT_REQ_NOTHING },
     2525        { "stream",     1002, RTGETOPT_REQ_NOTHING },
    23872526    };
    23882527    MEDIUMIOCOMMONOPT   CommonOpts = { NULL, DeviceType_Null, NULL };
     
    24052544                setCurrentSubcommand(HELP_SCOPE_MEDIUMIO_CAT);
    24062545                return handleMediumIOCat(a, GetState.iNext, &CommonOpts);
     2546            case 1002:
     2547                setCurrentSubcommand(HELP_SCOPE_MEDIUMIO_STREAM);
     2548                return handleMediumIOStream(a, GetState.iNext, &CommonOpts);
    24072549
    24082550            case VINF_GETOPT_NOT_OPTION:
  • trunk/src/VBox/Main/include/DataStreamImpl.h

    r74776 r74822  
    2222#include "DataStreamWrap.h"
    2323
     24#include <iprt/circbuf.h>
    2425#include <iprt/semaphore.h>
    2526
     
    5152
    5253private:
    53     /** Maximum number of bytes the buffer can hold. */
    54     unsigned long     m_aBufferSize;
    5554    /** The temporary buffer the conversion process writes into and the user reads from. */
    56     std::vector<BYTE> m_aBuffer;
     55    PRTCIRCBUF        m_pBuffer;
    5756    /** Event semaphore for waiting until data is available. */
    5857    RTSEMEVENT        m_hSemEvtDataAvail;
  • trunk/src/VBox/Main/include/MediumIOImpl.h

    r74761 r74822  
    2020
    2121#include "MediumIOWrap.h"
     22#include "VirtualBoxBase.h"
     23#include "AutoCaller.h"
    2224
    2325class ATL_NO_VTABLE MediumIO :
     
    3436    /** @name Initializer & uninitializer.
    3537     * @{ */
    36     HRESULT initForMedium(Medium *pMedium, bool fWritable, com::Utf8Str const &rStrKeyId, com::Utf8Str const &rStrPassword);
     38    HRESULT initForMedium(Medium *pMedium, VirtualBox *pVirtualBox, bool fWritable,
     39                          com::Utf8Str const &rStrKeyId, com::Utf8Str const &rStrPassword);
    3740    void    uninit();
    3841    /** @} */
     
    6770    struct Data;
    6871    Data *m;
     72
     73    class StreamTask;
     74    friend class StreamTask;
    6975};
    7076
  • trunk/src/VBox/Main/src-server/MediumIOImpl.cpp

    r74763 r74822  
    2424#include "MediumImpl.h"
    2525#include "MediumLock.h"
     26#include "DataStreamImpl.h"
    2627#include "Global.h"
     28#include "ProgressImpl.h"
     29#include "VirtualBoxImpl.h"
    2730
    2831#include "AutoCaller.h"
    2932#include "Logging.h"
     33#include "ThreadTask.h"
    3034
    3135#include <iprt/fsvfs.h>
    3236#include <iprt/dvm.h>
     37#include <iprt/zero.h>
    3338#include <iprt/cpp/utils.h>
    3439
     
    4247struct MediumIO::Data
    4348{
    44     Data(Medium * const a_pMedium, bool a_fWritable, uint32_t a_cbSector = 512)
     49    Data(Medium * const a_pMedium, VirtualBox * const a_pVirtualBox, bool a_fWritable, uint32_t a_cbSector = 512)
    4550        : ptrMedium(a_pMedium)
     51        , ptrVirtualBox(a_pVirtualBox)
    4652        , fWritable(a_fWritable)
    4753        , cbSector(a_cbSector)
     
    5460    /** Reference to the medium we're accessing. */
    5561    ComPtr<Medium>                  ptrMedium;
     62    /** Reference to the VirtualBox object the medium is part of. */
     63    ComPtr<VirtualBox>              ptrVirtualBox;
    5664    /** Set if writable, clear if readonly. */
    5765    bool                            fWritable;
     
    7482
    7583
     84/**
     85 * MediumIO::StreamTask class for asynchronous convert to stream operation.
     86 *
     87 * @note Instances of this class must be created using new() because the
     88 *       task thread function will delete them when the task is complete.
     89 *
     90 * @note The constructor of this class adds a caller on the managed Medium
     91 *       object which is automatically released upon destruction.
     92 */
     93class MediumIO::StreamTask : public ThreadTask
     94{
     95public:
     96    StreamTask(MediumIO *pMediumIO, DataStream *pDataStream, Progress *pProgress, const char *pszFormat,
     97               MediumVariant_T fMediumVariant)
     98        : ThreadTask("StreamTask"),
     99          mVDOperationIfaces(NULL),
     100          mMediumIO(pMediumIO),
     101          mMediumCaller(pMediumIO->m->ptrMedium),
     102          m_pDataStream(pDataStream),
     103          m_fMediumVariant(fMediumVariant),
     104          m_strFormat(pszFormat),
     105          mProgress(pProgress),
     106          mVirtualBoxCaller(NULL)
     107    {
     108        AssertReturnVoidStmt(pMediumIO, mRC = E_FAIL);
     109        AssertReturnVoidStmt(pDataStream, mRC = E_FAIL);
     110        mRC = mMediumCaller.rc();
     111        if (FAILED(mRC))
     112            return;
     113
     114        /* Get strong VirtualBox reference, see below. */
     115        VirtualBox *pVirtualBox = pMediumIO->m->ptrVirtualBox;
     116        mVirtualBox = pVirtualBox;
     117        mVirtualBoxCaller.attach(pVirtualBox);
     118        mRC = mVirtualBoxCaller.rc();
     119        if (FAILED(mRC))
     120            return;
     121
     122        /* Set up a per-operation progress interface, can be used freely (for
     123         * binary operations you can use it either on the source or target). */
     124        if (mProgress)
     125        {
     126            mVDIfProgress.pfnProgress = pProgress->i_vdProgressCallback;
     127            int vrc = VDInterfaceAdd(&mVDIfProgress.Core,
     128                                     "Medium::Task::vdInterfaceProgress",
     129                                     VDINTERFACETYPE_PROGRESS,
     130                                     mProgress,
     131                                     sizeof(mVDIfProgress),
     132                                     &mVDOperationIfaces);
     133            AssertRC(vrc);
     134            if (RT_FAILURE(vrc))
     135                mRC = E_FAIL;
     136        }
     137    }
     138
     139    // Make all destructors virtual. Just in case.
     140    virtual ~StreamTask()
     141    {
     142        /* send the notification of completion.*/
     143        if (   isAsync()
     144            && !mProgress.isNull())
     145            mProgress->i_notifyComplete(mRC);
     146    }
     147
     148    HRESULT rc() const { return mRC; }
     149    bool isOk() const { return SUCCEEDED(rc()); }
     150
     151    const ComPtr<Progress>& GetProgressObject() const {return mProgress;}
     152
     153    /**
     154     * Implementation code for the "create base" task.
     155     * Used as function for execution from a standalone thread.
     156     */
     157    void handler()
     158    {
     159        LogFlowFuncEnter();
     160        try
     161        {
     162            mRC = executeTask(); /* (destructor picks up mRC, see above) */
     163            LogFlowFunc(("rc=%Rhrc\n", mRC));
     164        }
     165        catch (...)
     166        {
     167            LogRel(("Some exception in the function MediumIO::StreamTask:handler()\n"));
     168        }
     169
     170        LogFlowFuncLeave();
     171    }
     172
     173    PVDINTERFACE mVDOperationIfaces;
     174
     175    const ComObjPtr<MediumIO> mMediumIO;
     176    AutoCaller mMediumCaller;
     177
     178protected:
     179    HRESULT         mRC;
     180
     181    DataStream      *m_pDataStream;
     182    MediumVariant_T m_fMediumVariant;
     183    Utf8Str         m_strFormat;
     184
     185private:
     186    HRESULT executeTask();
     187
     188    const ComObjPtr<Progress> mProgress;
     189
     190    VDINTERFACEPROGRESS mVDIfProgress;
     191
     192    /* Must have a strong VirtualBox reference during a task otherwise the
     193     * reference count might drop to 0 while a task is still running. This
     194     * would result in weird behavior, including deadlocks due to uninit and
     195     * locking order issues. The deadlock often is not detectable because the
     196     * uninit uses event semaphores which sabotages deadlock detection. */
     197    ComObjPtr<VirtualBox> mVirtualBox;
     198    AutoCaller mVirtualBoxCaller;
     199
     200    static DECLCALLBACK(int) i_vdStreamOpen(void *pvUser, const char *pszLocation, uint32_t fOpen,
     201                                            PFNVDCOMPLETED pfnCompleted, void **ppStorage);
     202    static DECLCALLBACK(int) i_vdStreamClose(void *pvUser, void *pStorage);
     203    static DECLCALLBACK(int) i_vdStreamDelete(void *pvUser, const char *pcszFilename);
     204    static DECLCALLBACK(int) i_vdStreamMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove);
     205    static DECLCALLBACK(int) i_vdStreamGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace);
     206    static DECLCALLBACK(int) i_vdStreamGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime);
     207    static DECLCALLBACK(int) i_vdStreamGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize);
     208    static DECLCALLBACK(int) i_vdStreamSetSize(void *pvUser, void *pStorage, uint64_t cbSize);
     209    static DECLCALLBACK(int) i_vdStreamRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuffer, size_t cbBuffer,
     210                                            size_t *pcbRead);
     211    static DECLCALLBACK(int) i_vdStreamWrite(void *pvUser, void *pStorage, uint64_t uOffset,
     212                                             const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten);
     213    static DECLCALLBACK(int) i_vdStreamFlush(void *pvUser, void *pStorage);
     214};
     215
     216
     217/**
     218 * State of a streamed file.
     219 */
     220typedef struct STREAMFILE
     221{
     222    /** The data stream for this file state. */
     223    DataStream              *pDataStream;
     224    /** The last seen offset used to stream zeroes for non consecutive writes. */
     225    uint64_t                uOffsetLast;
     226    /** Set file size. */
     227    uint64_t                cbFile;
     228} STREAMFILE;
     229/** Pointer to the stream file state. */
     230typedef STREAMFILE *PSTREAMFILE;
     231
     232
     233
     234DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamOpen(void *pvUser, const char *pszLocation, uint32_t fOpen, PFNVDCOMPLETED pfnCompleted,
     235                                                       void **ppStorage)
     236{
     237    RT_NOREF2(pvUser, pszLocation);
     238
     239    /* Validate input. */
     240    AssertPtrReturn(ppStorage, VERR_INVALID_POINTER);
     241    AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
     242    AssertReturn((fOpen & RTFILE_O_ACCESS_MASK) == RTFILE_O_WRITE, VERR_INVALID_PARAMETER);
     243
     244    int rc = VINF_SUCCESS;
     245    PSTREAMFILE pStreamFile = (PSTREAMFILE)RTMemAllocZ(sizeof(*pStreamFile));
     246    if (RT_LIKELY(pStreamFile))
     247    {
     248        pStreamFile->pDataStream = (DataStream *)pvUser;
     249        pStreamFile->uOffsetLast = 0;
     250        pStreamFile->cbFile      = 0;
     251        *ppStorage = pStreamFile;
     252    }
     253    else
     254        rc = VERR_NO_MEMORY;
     255
     256    return rc;
     257}
     258
     259DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamClose(void *pvUser, void *pStorage)
     260{
     261    RT_NOREF(pvUser);
     262    PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage;
     263    int rc = VINF_SUCCESS;
     264
     265    /* Fill up to the configured file size. */
     266    if (pStreamFile->uOffsetLast < pStreamFile->cbFile)
     267    {
     268        do
     269        {
     270            size_t cbThisWrite = RT_MIN(pStreamFile->cbFile - pStreamFile->uOffsetLast, sizeof(g_abRTZero64K));
     271            size_t cbWritten = 0;
     272
     273            rc = pStreamFile->pDataStream->i_write(&g_abRTZero64K[0], cbThisWrite, &cbWritten);
     274            if (RT_SUCCESS(rc))
     275                pStreamFile->uOffsetLast += cbWritten;
     276
     277        } while (   RT_SUCCESS(rc)
     278                 && pStreamFile->uOffsetLast < pStreamFile->cbFile);
     279    }
     280
     281    int rc2 = pStreamFile->pDataStream->i_close();
     282    if (RT_SUCCESS(rc))
     283        rc = rc2;
     284
     285    RTMemFree(pStreamFile);
     286    return rc;
     287}
     288
     289DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamDelete(void *pvUser, const char *pcszFilename)
     290{
     291    NOREF(pvUser);
     292    NOREF(pcszFilename);
     293    AssertFailedReturn(VERR_NOT_SUPPORTED);
     294}
     295
     296DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
     297{
     298    NOREF(pvUser);
     299    NOREF(pcszSrc);
     300    NOREF(pcszDst);
     301    NOREF(fMove);
     302    AssertFailedReturn(VERR_NOT_SUPPORTED);
     303}
     304
     305DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
     306{
     307    NOREF(pvUser);
     308    NOREF(pcszFilename);
     309    AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
     310    *pcbFreeSpace = INT64_MAX;
     311    return VINF_SUCCESS;
     312}
     313
     314DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
     315{
     316    NOREF(pvUser);
     317    NOREF(pcszFilename);
     318    AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
     319    AssertFailedReturn(VERR_NOT_SUPPORTED);
     320}
     321
     322DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
     323{
     324    NOREF(pvUser);
     325    PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage;
     326    AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
     327
     328    *pcbSize = pStreamFile->cbFile;
     329    return VINF_SUCCESS;
     330}
     331
     332DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
     333{
     334    RT_NOREF(pvUser);
     335    PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage;
     336
     337    /* Reducing the size is not supported. */
     338    int rc = VINF_SUCCESS;
     339    if (pStreamFile->cbFile < cbSize)
     340        pStreamFile->cbFile = cbSize;
     341    else
     342        rc = VERR_NOT_SUPPORTED;
     343
     344    return rc;
     345}
     346
     347DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuffer, size_t cbBuffer,
     348                                                       size_t *pcbRead)
     349{
     350    NOREF(pvUser);
     351    NOREF(pStorage);
     352    NOREF(uOffset);
     353    NOREF(cbBuffer);
     354    NOREF(pcbRead);
     355    AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
     356    AssertFailedReturn(VERR_NOT_SUPPORTED);
     357}
     358
     359DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamWrite(void *pvUser, void *pStorage, uint64_t uOffset, const void *pvBuffer, size_t cbBuffer,
     360                                                        size_t *pcbWritten)
     361{
     362    RT_NOREF(pvUser);
     363    PSTREAMFILE pStreamFile = (PSTREAMFILE)pStorage;
     364    int rc = VINF_SUCCESS;
     365
     366    /* Fill up to the new offset if there is non consecutive access. */
     367    if (pStreamFile->uOffsetLast < uOffset)
     368    {
     369        do
     370        {
     371            size_t cbThisWrite = RT_MIN(uOffset - pStreamFile->uOffsetLast, sizeof(g_abRTZero64K));
     372            size_t cbWritten = 0;
     373
     374            rc = pStreamFile->pDataStream->i_write(&g_abRTZero64K[0], cbThisWrite, &cbWritten);
     375            if (RT_SUCCESS(rc))
     376                pStreamFile->uOffsetLast += cbWritten;
     377
     378        } while (   RT_SUCCESS(rc)
     379                 && pStreamFile->uOffsetLast < uOffset);
     380    }
     381
     382    if (RT_SUCCESS(rc))
     383    {
     384        if (pcbWritten)
     385            rc = pStreamFile->pDataStream->i_write(pvBuffer, cbBuffer, pcbWritten);
     386        else
     387        {
     388            const uint8_t *pbBuf = (const uint8_t *)pvBuffer;
     389            size_t cbLeft = cbBuffer;
     390            size_t cbWritten = 0;
     391            while (   cbLeft > 0
     392                   && RT_SUCCESS(rc))
     393            {
     394                rc = pStreamFile->pDataStream->i_write(pbBuf, cbLeft, &cbWritten);
     395                if (RT_SUCCESS(rc))
     396                {
     397                    pbBuf  += cbWritten;
     398                    cbLeft -= cbWritten;
     399                }
     400            }
     401        }
     402
     403        if (RT_SUCCESS(rc))
     404        {
     405            size_t cbWritten = pcbWritten ? *pcbWritten : cbBuffer;
     406
     407            /* Adjust file size. */
     408            if (uOffset + cbWritten > pStreamFile->cbFile)
     409                pStreamFile->cbFile = uOffset + cbWritten;
     410
     411            pStreamFile->uOffsetLast = uOffset + cbWritten;
     412        }
     413    }
     414
     415    return rc;
     416}
     417
     418DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamFlush(void *pvUser, void *pStorage)
     419{
     420    NOREF(pvUser);
     421    NOREF(pStorage);
     422    return VINF_SUCCESS;
     423}
     424
     425/**
     426 * Implementation code for the "stream" task.
     427 */
     428HRESULT MediumIO::StreamTask::executeTask()
     429{
     430    HRESULT hrc = S_OK;
     431    VDINTERFACEIO IfsOutputIO;
     432    PVDINTERFACE pIfsOp = NULL;
     433    PVDISK pDstDisk;
     434
     435    IfsOutputIO.pfnOpen                   = i_vdStreamOpen;
     436    IfsOutputIO.pfnClose                  = i_vdStreamClose;
     437    IfsOutputIO.pfnDelete                 = i_vdStreamDelete;
     438    IfsOutputIO.pfnMove                   = i_vdStreamMove;
     439    IfsOutputIO.pfnGetFreeSpace           = i_vdStreamGetFreeSpace;
     440    IfsOutputIO.pfnGetModificationTime    = i_vdStreamGetModificationTime;
     441    IfsOutputIO.pfnGetSize                = i_vdStreamGetSize;
     442    IfsOutputIO.pfnSetSize                = i_vdStreamSetSize;
     443    IfsOutputIO.pfnReadSync               = i_vdStreamRead;
     444    IfsOutputIO.pfnWriteSync              = i_vdStreamWrite;
     445    IfsOutputIO.pfnFlushSync              = i_vdStreamFlush;
     446    VDInterfaceAdd(&IfsOutputIO.Core, "stream", VDINTERFACETYPE_IO,
     447                   m_pDataStream, sizeof(VDINTERFACEIO), &pIfsOp);
     448
     449    int vrc = VDCreate(NULL, VDTYPE_HDD, &pDstDisk);
     450    if (RT_SUCCESS(vrc))
     451    {
     452        /* Create the output image */
     453        vrc = VDCopy(mMediumIO->m->pHdd, VD_LAST_IMAGE, pDstDisk, m_strFormat.c_str(),
     454                     "stream", false, 0, m_fMediumVariant, NULL,
     455                     VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_SEQUENTIAL, NULL,
     456                     pIfsOp, NULL);
     457        if (RT_FAILURE(vrc))
     458            hrc = mMediumIO->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
     459                                          tr("Failed to convert and stream disk image"));
     460
     461        VDDestroy(pDstDisk);
     462    }
     463    else
     464        hrc = mMediumIO->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
     465                                      tr("Failed to create destination disk container"));
     466
     467    return hrc;
     468}
     469
     470
    76471/*********************************************************************************************************************************
    77472*   Boilerplate constructor & destructor                                                                                         *
     
    103498 *
    104499 * @param   pMedium         Pointer to the medium to access.
     500 * @param   pMedium         Pointer to the VirtualBox object the medium is part of.
    105501 * @param   fWritable       Read-write (true) or readonly (false) access.
    106502 * @param   rStrKeyId       The key ID for an encrypted medium.  Empty if not
     
    110506 *
    111507 */
    112 HRESULT MediumIO::initForMedium(Medium *pMedium, bool fWritable, com::Utf8Str const &rStrKeyId, com::Utf8Str const &rStrPassword)
    113 {
    114     LogFlowThisFunc(("pMedium=%p fWritable=%RTbool\n", pMedium, fWritable));
     508HRESULT MediumIO::initForMedium(Medium *pMedium, VirtualBox *pVirtualBox, bool fWritable,
     509                                com::Utf8Str const &rStrKeyId, com::Utf8Str const &rStrPassword)
     510{
     511    LogFlowThisFunc(("pMedium=%p pVirtualBox=%p fWritable=%RTbool\n", pMedium, pVirtualBox, fWritable));
    115512    CheckComArgExpr(rStrPassword, rStrPassword.isEmpty() == rStrKeyId.isEmpty()); /* checked by caller */
    116513
     
    125522     */
    126523    HRESULT hrc = S_OK;
    127     m = new(std::nothrow) Data(pMedium, fWritable);
     524    m = new(std::nothrow) Data(pMedium, pVirtualBox, fWritable);
    128525    if (m)
    129526    {
     
    400797                                  ComPtr<IProgress> &aProgress)
    401798{
    402     RT_NOREF(aFormat, aVariant, aBufferSize, aStream, aProgress);
    403     return E_NOTIMPL;
     799    HRESULT rc = S_OK;
     800    ComObjPtr<Progress> pProgress;
     801    ComObjPtr<DataStream> pDataStream;
     802    MediumIO::StreamTask *pTask = NULL;
     803
     804    pProgress.createObject();
     805    pDataStream.createObject();
     806
     807    try
     808    {
     809        rc = pDataStream->init(aBufferSize);
     810        if (FAILED(rc))
     811            throw rc;
     812
     813        ULONG mediumVariantFlags = 0;
     814
     815        if (aVariant.size())
     816        {
     817            for (size_t i = 0; i < aVariant.size(); i++)
     818                mediumVariantFlags |= (ULONG)aVariant[i];
     819        }
     820
     821        /* setup task object to carry out the operation asynchronously */
     822        pTask = new MediumIO::StreamTask(this, pDataStream, pProgress,
     823                                         aFormat.c_str(), (MediumVariant_T)mediumVariantFlags);
     824        rc = pTask->rc();
     825        AssertComRC(rc);
     826        if (FAILED(rc))
     827            throw rc;
     828    }
     829    catch (HRESULT aRC) { rc = aRC; }
     830
     831    if (SUCCEEDED(rc))
     832    {
     833        rc = pTask->createThread();
     834
     835        if (SUCCEEDED(rc))
     836        {
     837            pDataStream.queryInterfaceTo(aStream.asOutParam());
     838            pProgress.queryInterfaceTo(aProgress.asOutParam());
     839        }
     840    }
     841    else if (pTask != NULL)
     842        delete pTask;
     843
     844    return rc;
    404845}
    405846
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r74353 r74822  
    38403840    if (SUCCEEDED(hrc))
    38413841    {
    3842         hrc = ptrIO->initForMedium(this, aWritable != FALSE, strKeyId, aPassword);
     3842        hrc = ptrIO->initForMedium(this, m->pVirtualBox, aWritable != FALSE, strKeyId, aPassword);
    38433843        if (SUCCEEDED(hrc))
    38443844            ptrIO.queryInterfaceTo(aMediumIO.asOutParam());
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette