- Timestamp:
- Oct 12, 2018 6:40:09 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/doc/manual/en_US/man_VBoxManage-mediumio.xml
r73276 r74822 56 56 <arg>--offset=<replaceable>byte-offset</replaceable></arg> 57 57 <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> 58 71 <arg>--output=<replaceable>-|filename</replaceable></arg> 59 72 </cmdsynopsis> … … 126 139 </refsect2> 127 140 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 128 161 </refsect1> 129 162 -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
r74354 r74822 2373 2373 } 2374 2374 2375 /** 2376 * mediumio stream 2377 */ 2378 static 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 2375 2513 2376 2514 RTEXITCODE handleMediumIO(HandlerArg *a) … … 2385 2523 { "formatfat", 1000, RTGETOPT_REQ_NOTHING }, 2386 2524 { "cat", 1001, RTGETOPT_REQ_NOTHING }, 2525 { "stream", 1002, RTGETOPT_REQ_NOTHING }, 2387 2526 }; 2388 2527 MEDIUMIOCOMMONOPT CommonOpts = { NULL, DeviceType_Null, NULL }; … … 2405 2544 setCurrentSubcommand(HELP_SCOPE_MEDIUMIO_CAT); 2406 2545 return handleMediumIOCat(a, GetState.iNext, &CommonOpts); 2546 case 1002: 2547 setCurrentSubcommand(HELP_SCOPE_MEDIUMIO_STREAM); 2548 return handleMediumIOStream(a, GetState.iNext, &CommonOpts); 2407 2549 2408 2550 case VINF_GETOPT_NOT_OPTION: -
trunk/src/VBox/Main/include/DataStreamImpl.h
r74776 r74822 22 22 #include "DataStreamWrap.h" 23 23 24 #include <iprt/circbuf.h> 24 25 #include <iprt/semaphore.h> 25 26 … … 51 52 52 53 private: 53 /** Maximum number of bytes the buffer can hold. */54 unsigned long m_aBufferSize;55 54 /** The temporary buffer the conversion process writes into and the user reads from. */ 56 std::vector<BYTE> m_aBuffer;55 PRTCIRCBUF m_pBuffer; 57 56 /** Event semaphore for waiting until data is available. */ 58 57 RTSEMEVENT m_hSemEvtDataAvail; -
trunk/src/VBox/Main/include/MediumIOImpl.h
r74761 r74822 20 20 21 21 #include "MediumIOWrap.h" 22 #include "VirtualBoxBase.h" 23 #include "AutoCaller.h" 22 24 23 25 class ATL_NO_VTABLE MediumIO : … … 34 36 /** @name Initializer & uninitializer. 35 37 * @{ */ 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); 37 40 void uninit(); 38 41 /** @} */ … … 67 70 struct Data; 68 71 Data *m; 72 73 class StreamTask; 74 friend class StreamTask; 69 75 }; 70 76 -
trunk/src/VBox/Main/src-server/MediumIOImpl.cpp
r74763 r74822 24 24 #include "MediumImpl.h" 25 25 #include "MediumLock.h" 26 #include "DataStreamImpl.h" 26 27 #include "Global.h" 28 #include "ProgressImpl.h" 29 #include "VirtualBoxImpl.h" 27 30 28 31 #include "AutoCaller.h" 29 32 #include "Logging.h" 33 #include "ThreadTask.h" 30 34 31 35 #include <iprt/fsvfs.h> 32 36 #include <iprt/dvm.h> 37 #include <iprt/zero.h> 33 38 #include <iprt/cpp/utils.h> 34 39 … … 42 47 struct MediumIO::Data 43 48 { 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) 45 50 : ptrMedium(a_pMedium) 51 , ptrVirtualBox(a_pVirtualBox) 46 52 , fWritable(a_fWritable) 47 53 , cbSector(a_cbSector) … … 54 60 /** Reference to the medium we're accessing. */ 55 61 ComPtr<Medium> ptrMedium; 62 /** Reference to the VirtualBox object the medium is part of. */ 63 ComPtr<VirtualBox> ptrVirtualBox; 56 64 /** Set if writable, clear if readonly. */ 57 65 bool fWritable; … … 74 82 75 83 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 */ 93 class MediumIO::StreamTask : public ThreadTask 94 { 95 public: 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 178 protected: 179 HRESULT mRC; 180 181 DataStream *m_pDataStream; 182 MediumVariant_T m_fMediumVariant; 183 Utf8Str m_strFormat; 184 185 private: 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 */ 220 typedef 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. */ 230 typedef STREAMFILE *PSTREAMFILE; 231 232 233 234 DECLCALLBACK(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 259 DECLCALLBACK(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 289 DECLCALLBACK(int) MediumIO::StreamTask::i_vdStreamDelete(void *pvUser, const char *pcszFilename) 290 { 291 NOREF(pvUser); 292 NOREF(pcszFilename); 293 AssertFailedReturn(VERR_NOT_SUPPORTED); 294 } 295 296 DECLCALLBACK(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 305 DECLCALLBACK(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 314 DECLCALLBACK(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 322 DECLCALLBACK(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 332 DECLCALLBACK(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 347 DECLCALLBACK(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 359 DECLCALLBACK(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 418 DECLCALLBACK(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 */ 428 HRESULT 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 76 471 /********************************************************************************************************************************* 77 472 * Boilerplate constructor & destructor * … … 103 498 * 104 499 * @param pMedium Pointer to the medium to access. 500 * @param pMedium Pointer to the VirtualBox object the medium is part of. 105 501 * @param fWritable Read-write (true) or readonly (false) access. 106 502 * @param rStrKeyId The key ID for an encrypted medium. Empty if not … … 110 506 * 111 507 */ 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)); 508 HRESULT 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)); 115 512 CheckComArgExpr(rStrPassword, rStrPassword.isEmpty() == rStrKeyId.isEmpty()); /* checked by caller */ 116 513 … … 125 522 */ 126 523 HRESULT hrc = S_OK; 127 m = new(std::nothrow) Data(pMedium, fWritable);524 m = new(std::nothrow) Data(pMedium, pVirtualBox, fWritable); 128 525 if (m) 129 526 { … … 400 797 ComPtr<IProgress> &aProgress) 401 798 { 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; 404 845 } 405 846 -
trunk/src/VBox/Main/src-server/MediumImpl.cpp
r74353 r74822 3840 3840 if (SUCCEEDED(hrc)) 3841 3841 { 3842 hrc = ptrIO->initForMedium(this, aWritable != FALSE, strKeyId, aPassword);3842 hrc = ptrIO->initForMedium(this, m->pVirtualBox, aWritable != FALSE, strKeyId, aPassword); 3843 3843 if (SUCCEEDED(hrc)) 3844 3844 ptrIO.queryInterfaceTo(aMediumIO.asOutParam());
Note:
See TracChangeset
for help on using the changeset viewer.