- Timestamp:
- Mar 7, 2018 11:20:00 AM (7 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r71231 r71251 219 219 } 220 220 221 const char*GetSource() const222 { 223 return mSource .c_str();224 } 225 226 const char*GetFilter() const227 { 228 return mFilter .c_str();221 Utf8Str GetSource() const 222 { 223 return mSource; 224 } 225 226 Utf8Str GetFilter() const 227 { 228 return mFilter; 229 229 } 230 230 … … 1767 1767 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 1768 1768 1769 Utf8Str strSource;1770 1769 const char *pszDst = NULL; 1771 1770 bool fDryRun = false; … … 1853 1852 for (unsigned long s = 0; s < vecSources.size(); s++) 1854 1853 { 1855 char *pszSrc = RTStrDup(vecSources[s].GetSource()); 1856 AssertPtrBreakStmt(pszSrc, vrc = VERR_NO_MEMORY); 1857 const char *pszFilter = vecSources[s].GetFilter(); 1858 RT_NOREF(pszFilter); 1859 /* pszFilter can be NULL if not set. */ 1854 Utf8Str strSrc = vecSources[s].GetSource(); 1855 Utf8Str strFilter = vecSources[s].GetFilter(); 1856 RT_NOREF(strFilter); 1857 /* strFilter can be NULL if not set. */ 1860 1858 1861 1859 if (fHostToGuest) 1862 1860 { 1863 if (RTFileExists( pszSrc))1861 if (RTFileExists(strSrc.c_str())) 1864 1862 { 1865 1863 SafeArray<FileCopyFlag_T> copyFlags; 1866 rc = pCtx->pGuestSession->FileCopyToGuest(Bstr( pszSrc).raw(), Bstr(pszDst).raw(),1864 rc = pCtx->pGuestSession->FileCopyToGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(), 1867 1865 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1868 1866 } 1869 else if (RTDirExists( pszSrc))1867 else if (RTDirExists(strSrc.c_str())) 1870 1868 { 1871 1869 SafeArray<DirectoryCopyFlag_T> copyFlags; 1872 1870 copyFlags.push_back(DirectoryCopyFlag_CopyIntoExisting); 1873 rc = pCtx->pGuestSession->DirectoryCopyToGuest(Bstr( pszSrc).raw(), Bstr(pszDst).raw(),1871 rc = pCtx->pGuestSession->DirectoryCopyToGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(), 1874 1872 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1875 1873 } 1876 1874 else if (pCtx->cVerbose) 1877 RTPrintf("Warning: \"%s\" does not exist or is not a file/directory, skipping ...\n", pszSrc);1875 RTPrintf("Warning: \"%s\" does not exist or is not a file/directory, skipping ...\n", strSrc.c_str()); 1878 1876 } 1879 1877 else 1880 1878 { 1881 SafeArray<FileCopyFlag_T> copyFlags; 1882 rc = pCtx->pGuestSession->FileCopyFromGuest(Bstr(pszSrc).raw(), Bstr(pszDst).raw(), 1883 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1879 if ( strSrc.endsWith("/") 1880 || strSrc.endsWith("\\")) 1881 { 1882 SafeArray<DirectoryCopyFlag_T> copyFlags; 1883 copyFlags.push_back(DirectoryCopyFlag_CopyIntoExisting); 1884 rc = pCtx->pGuestSession->DirectoryCopyFromGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(), 1885 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1886 } 1887 else 1888 { 1889 SafeArray<FileCopyFlag_T> copyFlags; 1890 rc = pCtx->pGuestSession->FileCopyFromGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(), 1891 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam()); 1892 } 1884 1893 } 1885 1894 } -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r71231 r71251 82 82 /** @name File handling primitives. 83 83 * @{ */ 84 int fileCopyToGuestEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, PRTFILE pFile, 85 uint64_t cbOffset, uint64_t cbSize); /**< r=bird: 'cbOffset' makes no sense what so ever. It should be 'off', or do you mean sizeof(uint64_t)? */ 86 int fileCopyToGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags); 84 int fileCopyFromEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, 85 PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize); 86 int fileCopyFrom(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags); 87 int fileCopyToEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, PRTFILE pFile, 88 uint64_t cbOffset, uint64_t cbSize); /**< r=bird: 'cbOffset' makes no sense what so ever. It should be 'off', or do you mean sizeof(uint64_t)? */ 89 int fileCopyTo(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags); 87 90 /** @} */ 88 91 … … 195 198 196 199 SessionTaskCopyFileTo(GuestSession *pSession, 197 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags);200 const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags); 198 201 SessionTaskCopyFileTo(GuestSession *pSession, 199 202 PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize, 200 const Utf8Str &strDest, uint32_t uFlags);203 const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags); 201 204 virtual ~SessionTaskCopyFileTo(void); 202 205 int Run(void); … … 204 207 protected: 205 208 206 Utf8Str mSource;207 PRTFILE mSourceFile;208 size_t mSourceOffset;209 uint64_t mSourceSize;210 Utf8Str mDest;211 uint32_t mCopyFileFlags;209 Utf8Str mSource; 210 PRTFILE mSourceFile; 211 size_t mSourceOffset; 212 uint64_t mSourceSize; 213 Utf8Str mDest; 214 FileCopyFlag_T mFileCopyFlags; 212 215 }; 213 216 … … 220 223 221 224 SessionTaskCopyFileFrom(GuestSession *pSession, 222 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags);225 const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags); 223 226 virtual ~SessionTaskCopyFileFrom(void); 224 227 int Run(void); … … 226 229 protected: 227 230 228 Utf8Str mSource;229 Utf8Str mDest;230 uint32_t mFlags;231 Utf8Str mSource; 232 Utf8Str mDest; 233 FileCopyFlag_T mFileCopyFlags; 231 234 }; 232 235 -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r71232 r71251 2600 2600 const std::vector<DirectoryCopyFlag_T> &aFlags, ComPtr<IProgress> &aProgress) 2601 2601 { 2602 RT_NOREF(aSource, aDestination, aFlags, aProgress); 2603 ReturnComNotImplemented(); 2602 LogFlowThisFuncEnter(); 2603 2604 if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0')) 2605 return setError(E_INVALIDARG, tr("No source directory specified")); 2606 2607 if (RT_UNLIKELY((aDestination.c_str()) == NULL || *(aDestination.c_str()) == '\0')) 2608 return setError(E_INVALIDARG, tr("No destination directory specified")); 2609 2610 uint32_t fFlags = DirectoryCopyFlag_None; 2611 if (aFlags.size()) 2612 { 2613 for (size_t i = 0; i < aFlags.size(); i++) 2614 fFlags |= aFlags[i]; 2615 } 2616 /** @todo Validate flags. */ 2617 2618 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 2619 2620 HRESULT hr = S_OK; 2621 2622 try 2623 { 2624 SessionTaskCopyDirFrom *pTask = NULL; 2625 ComObjPtr<Progress> pProgress; 2626 try 2627 { 2628 pTask = new SessionTaskCopyDirFrom(this /* GuestSession */, aSource, aDestination, "" /* strFilter */, 2629 (DirectoryCopyFlag_T)fFlags); 2630 } 2631 catch(...) 2632 { 2633 hr = setError(VBOX_E_IPRT_ERROR, tr("Failed to create SessionTaskCopyDirFrom object")); 2634 throw; 2635 } 2636 2637 hr = pTask->Init(Utf8StrFmt(tr("Copying directory \"%s\" from guest to \"%s\" on the host"), 2638 aSource.c_str(), aDestination.c_str())); 2639 if (FAILED(hr)) 2640 { 2641 delete pTask; 2642 hr = setError(VBOX_E_IPRT_ERROR, 2643 tr("Creating progress object for SessionTaskCopyDirFrom object failed")); 2644 throw hr; 2645 } 2646 2647 hr = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER); 2648 2649 if (SUCCEEDED(hr)) 2650 { 2651 /* Return progress to the caller. */ 2652 pProgress = pTask->GetProgressObject(); 2653 hr = pProgress.queryInterfaceTo(aProgress.asOutParam()); 2654 } 2655 else 2656 hr = setError(VBOX_E_IPRT_ERROR, 2657 tr("Starting thread for copying directory \"%s\" from guest to \"%s\" on the host failed"), 2658 aSource.c_str(), aDestination.c_str()); 2659 } 2660 catch(std::bad_alloc &) 2661 { 2662 hr = E_OUTOFMEMORY; 2663 } 2664 catch(HRESULT eHR) 2665 { 2666 hr = eHR; 2667 LogFlowThisFunc(("Exception was caught in the function\n")); 2668 } 2669 2670 return hr; 2604 2671 } 2605 2672 -
trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
r71242 r71251 261 261 262 262 /** 263 * Copies a file from the guest to the host, extended version. 264 * 265 * @return VBox status code. 266 * @param strSource Full path of source file on the guest to copy. 267 * @param strDest Full destination path and file name (host style) to copy file to. 268 * @param enmFileCopyFlags File copy flags. Currently not used. 269 * @param pFile Destination file handle to use for accessing the host file. 270 * The caller is responsible of opening / closing the file accordingly. 271 * @param cbOffset Offset (in bytes) where to start copying the source file. 272 * Currently unused, must be 0. 273 * @param cbSize Size (in bytes) to copy from the source file. 274 * Currently unused, must be 0. 275 */ 276 int GuestSessionTask::fileCopyFromEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, 277 PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize) 278 { 279 RT_NOREF(enmFileCopyFlags, cbOffset, cbSize); 280 281 AssertReturn(cbOffset == 0, VERR_NOT_IMPLEMENTED); 282 AssertReturn(cbSize == 0, VERR_NOT_IMPLEMENTED); 283 284 RTMSINTERVAL msTimeout = 30 * 1000; /** @todo 30s timeout for all actions. Make this configurable? */ 285 286 /* 287 * Note: There will be races between querying file size + reading the guest file's 288 * content because we currently *do not* lock down the guest file when doing the 289 * actual operations. 290 ** @todo Use the IGuestFile API for locking down the file on the guest! 291 */ 292 GuestFsObjData objData; 293 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS; 294 int rc = mSession->i_fileQueryInfoInternal(strSource, false /*fFollowSymlinks*/, objData, &rcGuest); 295 if (RT_FAILURE(rc)) 296 { 297 switch (rc) 298 { 299 case VERR_GSTCTL_GUEST_ERROR: 300 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 301 break; 302 303 default: 304 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 305 Utf8StrFmt(GuestSession::tr("Querying guest file information for \"%s\" failed: %Rrc"), 306 strSource.c_str(), rc)); 307 break; 308 } 309 } 310 else if (objData.mType != FsObjType_File) /* Only single files are supported at the moment. */ 311 { 312 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 313 Utf8StrFmt(GuestSession::tr("Object \"%s\" on the guest is not a file"), strSource.c_str())); 314 rc = VERR_NOT_A_FILE; 315 } 316 317 if (RT_FAILURE(rc)) 318 return rc; 319 320 GuestProcessStartupInfo procInfo; 321 procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"), 322 strSource.c_str(), strDest.c_str(), objData.mObjectSize); 323 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT); 324 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut; 325 326 /* Set arguments.*/ 327 procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */ 328 procInfo.mArguments.push_back(strSource); /* Which file to output? */ 329 330 /* Startup process. */ 331 ComObjPtr<GuestProcess> pProcess; 332 rc = mSession->i_processCreateExInternal(procInfo, pProcess); 333 if (RT_SUCCESS(rc)) 334 rc = pProcess->i_startProcess(msTimeout, &rcGuest); 335 336 if (RT_FAILURE(rc)) 337 { 338 switch (rc) 339 { 340 case VERR_GSTCTL_GUEST_ERROR: 341 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 342 break; 343 344 default: 345 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 346 Utf8StrFmt(GuestSession::tr( 347 "Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 348 strSource.c_str(), rc)); 349 break; 350 } 351 352 return rc; 353 } 354 355 ProcessWaitResult_T waitRes; 356 BYTE byBuf[_64K]; 357 358 BOOL fCanceled = FALSE; 359 uint64_t cbWrittenTotal = 0; 360 uint64_t cbToRead = objData.mObjectSize; 361 362 for (;;) 363 { 364 rc = pProcess->i_waitFor(ProcessWaitForFlag_StdOut, msTimeout, waitRes, &rcGuest); 365 if (RT_FAILURE(rc)) 366 { 367 switch (rc) 368 { 369 case VERR_GSTCTL_GUEST_ERROR: 370 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 371 break; 372 373 default: 374 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 375 Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 376 strSource.c_str(), rc)); 377 break; 378 } 379 380 break; 381 } 382 383 if ( waitRes == ProcessWaitResult_StdOut 384 || waitRes == ProcessWaitResult_WaitFlagNotSupported) 385 { 386 /* If the guest does not support waiting for stdin, we now yield in 387 * order to reduce the CPU load due to busy waiting. */ 388 if (waitRes == ProcessWaitResult_WaitFlagNotSupported) 389 RTThreadYield(); /* Optional, don't check rc. */ 390 391 uint32_t cbRead = 0; /* readData can return with VWRN_GSTCTL_OBJECTSTATE_CHANGED. */ 392 rc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 393 msTimeout, byBuf, sizeof(byBuf), 394 &cbRead, &rcGuest); 395 if (RT_FAILURE(rc)) 396 { 397 switch (rc) 398 { 399 case VERR_GSTCTL_GUEST_ERROR: 400 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 401 break; 402 403 default: 404 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 405 Utf8StrFmt(GuestSession::tr("Reading from guest file \"%s\" (offset %RU64) failed: %Rrc"), 406 strSource.c_str(), cbWrittenTotal, rc)); 407 break; 408 } 409 410 break; 411 } 412 413 if (cbRead) 414 { 415 rc = RTFileWrite(*pFile, byBuf, cbRead, NULL /* No partial writes */); 416 if (RT_FAILURE(rc)) 417 { 418 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 419 Utf8StrFmt(GuestSession::tr("Writing to host file \"%s\" (%RU64 bytes left) failed: %Rrc"), 420 strDest.c_str(), cbToRead, rc)); 421 break; 422 } 423 424 /* Only subtract bytes reported written by the guest. */ 425 Assert(cbToRead >= cbRead); 426 cbToRead -= cbRead; 427 428 /* Update total bytes written to the guest. */ 429 cbWrittenTotal += cbRead; 430 Assert(cbWrittenTotal <= (uint64_t)objData.mObjectSize); 431 432 /* Did the user cancel the operation above? */ 433 if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled))) 434 && fCanceled) 435 break; 436 437 rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)objData.mObjectSize / 100.0))); 438 if (RT_FAILURE(rc)) 439 break; 440 } 441 } 442 else 443 break; 444 445 } /* for */ 446 447 LogFlowThisFunc(("rc=%Rrc, rcGuest=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n", 448 rc, rcGuest, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead)); 449 450 /* 451 * Wait on termination of guest process until it completed all operations. 452 */ 453 if ( !fCanceled 454 || RT_SUCCESS(rc)) 455 { 456 rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &rcGuest); 457 if ( RT_FAILURE(rc) 458 || waitRes != ProcessWaitResult_Terminate) 459 { 460 if (RT_FAILURE(rc)) 461 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 462 Utf8StrFmt( 463 GuestSession::tr("Waiting on termination for copying file \"%s\" from guest failed: %Rrc"), 464 strSource.c_str(), rc)); 465 else 466 { 467 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 468 Utf8StrFmt(GuestSession::tr( 469 "Waiting on termination for copying file \"%s\" from guest failed with wait result %ld"), 470 strSource.c_str(), waitRes)); 471 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 472 } 473 } 474 } 475 476 if (RT_FAILURE(rc)) 477 return rc; 478 479 /** @todo this code sequence is duplicated in CopyTo */ 480 ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally; 481 HRESULT hrc = pProcess->COMGETTER(Status(&procStatus)); 482 if (!SUCCEEDED(hrc)) 483 procStatus = ProcessStatus_TerminatedAbnormally; 484 485 LONG exitCode = 42424242; 486 hrc = pProcess->COMGETTER(ExitCode(&exitCode)); 487 if (!SUCCEEDED(hrc)) 488 exitCode = 42424242; 489 490 if ( procStatus != ProcessStatus_TerminatedNormally 491 || exitCode != 0) 492 { 493 LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode)); 494 if (procStatus == ProcessStatus_TerminatedNormally) 495 rc = GuestProcessTool::i_exitCodeToRc(procInfo, exitCode); 496 else 497 rc = VERR_GENERAL_FAILURE; 498 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 499 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to host failed: %Rrc"), 500 strSource.c_str(), rc)); 501 } 502 /* 503 * Even if we succeeded until here make sure to check whether we really transfered 504 * everything. 505 */ 506 else if ( objData.mObjectSize > 0 507 && cbWrittenTotal == 0) 508 { 509 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write 510 * to the destination -> access denied. */ 511 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 512 Utf8StrFmt(GuestSession::tr("Writing guest file \"%s\" to host to \"%s\" failed: Access denied"), 513 strSource.c_str(), strDest.c_str())); 514 rc = VERR_ACCESS_DENIED; 515 } 516 else if (cbWrittenTotal < (uint64_t)objData.mObjectSize) 517 { 518 /* If we did not copy all let the user know. */ 519 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 520 Utf8StrFmt(GuestSession::tr("Copying guest file \"%s\" to host to \"%s\" failed (%RU64/%RI64 bytes transfered)"), 521 strSource.c_str(), strDest.c_str(), cbWrittenTotal, objData.mObjectSize)); 522 rc = VERR_INTERRUPTED; 523 } 524 525 return rc; 526 } 527 528 /** 529 * Copies a file from the guest to the host. 530 * 531 * @return VBox status code. 532 * @param strSource Full path of source file on the guest to copy. 533 * @param strDest Full destination path and file name (host style) to copy file to. 534 * @param enmFileCopyFlags File copy flags. 535 */ 536 int GuestSessionTask::fileCopyFrom(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags) 537 { 538 RTFILE hFile; 539 int rc = RTFileOpen(&hFile, strDest.c_str(), 540 RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */ 541 if (RT_FAILURE(rc)) 542 { 543 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 544 Utf8StrFmt(GuestSession::tr("Opening/creating destination file on host \"%s\" failed: %Rrc"), 545 strDest.c_str(), rc)); 546 return rc; 547 } 548 549 rc = fileCopyFromEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset, unused */, 0 /* Size, unused */); 550 551 int rc2 = RTFileClose(hFile); 552 AssertRC(rc2); 553 554 return rc; 555 } 556 557 /** 263 558 * Copies a file from the host to the guest, extended version. 264 559 * … … 272 567 * @param cbSize Size (in bytes) to copy from the source file. 273 568 */ 274 int GuestSessionTask::fileCopyTo GuestEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,275 569 int GuestSessionTask::fileCopyToEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, 570 PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize) 276 571 { 277 572 /** @todo Implement sparse file support? */ … … 537 832 * @param enmFileCopyFlags File copy flags. 538 833 */ 539 int GuestSessionTask::fileCopyTo Guest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)834 int GuestSessionTask::fileCopyTo(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags) 540 835 { 541 836 int rc; … … 571 866 } 572 867 else 573 rc = fileCopyTo GuestEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset */, cbSize);868 rc = fileCopyToEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset */, cbSize); 574 869 575 870 RTFileClose(hFile); … … 629 924 } 630 925 926 SessionTaskCopyDirFrom::SessionTaskCopyDirFrom(GuestSession *pSession, const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter, 927 DirectoryCopyFlag_T enmDirCopyFlags) 928 : GuestSessionTask(pSession) 929 , mSource(strSource) 930 , mDest(strDest) 931 , mFilter(strFilter) 932 , mDirCopyFlags(enmDirCopyFlags) 933 { 934 m_strTaskName = "gctlCpyDirFrm"; 935 } 936 937 SessionTaskCopyDirFrom::~SessionTaskCopyDirFrom(void) 938 { 939 940 } 941 942 /** 943 * Copys a directory (tree) from guest to the host. 944 * 945 * @return IPRT status code. 946 * @param strSource Source directory on the guest to copy to the host. 947 * @param strFilter DOS-style wildcard filter (?, *). Optional. 948 * @param strDest Destination directory on the host. 949 * @param fRecursive, Whether to recursively copy the directory contents or not. 950 * @param fFollowSymlinks Whether to follow symlinks or not. 951 * @param strSubDir Current sub directory to handle. Needs to NULL and only 952 * is needed for recursion. 953 */ 954 int SessionTaskCopyDirFrom::directoryCopyToHost(const Utf8Str &strSource, const Utf8Str &strFilter, 955 const Utf8Str &strDest, bool fRecursive, bool fFollowSymlinks, 956 const Utf8Str &strSubDir /* For recursion. */) 957 { 958 Utf8Str strSrcDir = strSource; 959 Utf8Str strDstDir = strDest; 960 Utf8Str strSrcSubDir = strSubDir; 961 962 /* Validation and sanity. */ 963 if ( !strSrcDir.endsWith("/") 964 && !strSrcDir.endsWith("\\")) 965 strSrcDir += "/"; 966 967 if ( !strDstDir.endsWith("/") 968 && !strDstDir.endsWith("\\")) 969 strDstDir+= "/"; 970 971 if ( strSrcSubDir.isNotEmpty() /* Optional, for recursion. */ 972 && !strSrcSubDir.endsWith("/") 973 && !strSrcSubDir.endsWith("\\")) 974 strSrcSubDir += "/"; 975 976 Utf8Str strSrcCur = strSrcDir + strSrcSubDir; 977 978 LogFlowFunc(("Entering '%s'\n", strSrcCur.c_str())); 979 980 int rc; 981 982 if (strSrcSubDir.isNotEmpty()) 983 { 984 const uint32_t fMode = 0700; /** @todo */ 985 986 rc = RTDirCreate(Utf8Str(strDstDir + strSrcSubDir).c_str(), fMode, 0); 987 if (RT_FAILURE(rc)) 988 return rc; 989 } 990 991 GuestDirectoryOpenInfo dirOpenInfo; 992 dirOpenInfo.mFilter = strFilter; 993 dirOpenInfo.mPath = strSrcCur; 994 dirOpenInfo.mFlags = 0; /** @todo Handle flags? */ 995 996 ComObjPtr <GuestDirectory> pDir; int rcGuest; 997 rc = mSession->i_directoryOpenInternal(dirOpenInfo, pDir, &rcGuest); 998 if (RT_FAILURE(rc)) 999 { 1000 switch (rc) 1001 { 1002 case VERR_INVALID_PARAMETER: 1003 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1004 Utf8StrFmt(GuestSession::tr("Opening directory \"%s\" failed: Invalid parameter"), dirOpenInfo.mPath.c_str())); 1005 break; 1006 1007 case VERR_GSTCTL_GUEST_ERROR: 1008 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 1009 break; 1010 1011 default: 1012 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1013 Utf8StrFmt(GuestSession::tr("Opening directory \"%s\" failed: %Rrc"), dirOpenInfo.mPath.c_str(), rc)); 1014 break; 1015 } 1016 1017 return rc; 1018 } 1019 1020 RT_NOREF(fRecursive, fFollowSymlinks); 1021 1022 ComObjPtr<GuestFsObjInfo> fsObjInfo; 1023 while (RT_SUCCESS(rc = pDir->i_readInternal(fsObjInfo, &rcGuest))) 1024 { 1025 com::Bstr aName; 1026 fsObjInfo->COMGETTER(Name)(aName.asOutParam()); 1027 LogFlowThisFunc(("strName=%ls\n", aName.raw())); 1028 } 1029 1030 if (rc == VERR_NO_MORE_FILES) /* Reading done? */ 1031 rc = VINF_SUCCESS; 1032 1033 pDir->i_closeInternal(&rcGuest); 1034 1035 LogFlowFunc(("Leaving '%s', rc=%Rrc\n", strSrcCur.c_str(), rc)); 1036 return rc; 1037 } 1038 1039 int SessionTaskCopyDirFrom::Run(void) 1040 { 1041 LogFlowThisFuncEnter(); 1042 1043 AutoCaller autoCaller(mSession); 1044 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1045 1046 const bool fRecursive = true; /** @todo Make this configurable. */ 1047 const bool fFollowSymlinks = true; /** @todo Make this configurable. */ 1048 const uint32_t fDirMode = 0700; /* Play safe by default. */ 1049 1050 int rc = VINF_SUCCESS; 1051 1052 /* Create the root target directory on the host. 1053 * The target directory might already exist on the host (based on mDirCopyFlags). */ 1054 const bool fExists = RTDirExists(mDest.c_str()); 1055 if ( fExists 1056 && !(mDirCopyFlags & DirectoryCopyFlag_CopyIntoExisting)) 1057 { 1058 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1059 Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" exists when it must not"), mDest.c_str())); 1060 rc = VERR_ALREADY_EXISTS; 1061 } 1062 else if (!fExists) 1063 { 1064 rc = RTDirCreate(mDest.c_str(), fDirMode, 0); 1065 if (RT_FAILURE(rc)) 1066 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1067 Utf8StrFmt(GuestSession::tr("Error creating destination directory \"%s\", rc=%Rrc"), 1068 mDest.c_str(), rc)); 1069 } 1070 1071 if (RT_FAILURE(rc)) 1072 return rc; 1073 1074 RTDIR hDir; 1075 rc = RTDirOpen(&hDir, mDest.c_str()); 1076 if (RT_FAILURE(rc)) 1077 { 1078 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1079 Utf8StrFmt(GuestSession::tr("Error opening destination directory \"%s\", rc=%Rrc"), 1080 mDest.c_str(), rc)); 1081 return rc; 1082 } 1083 1084 /* At this point the directory on the host was created and (hopefully) is ready 1085 * to receive further content. */ 1086 rc = directoryCopyToHost(mSource, mFilter, mDest, fRecursive, fFollowSymlinks, 1087 "" /* strSubDir; for recursion */); 1088 if (RT_SUCCESS(rc)) 1089 rc = setProgressSuccess(); 1090 1091 RTDirClose(hDir); 1092 1093 LogFlowFuncLeaveRC(rc); 1094 return rc; 1095 } 1096 631 1097 SessionTaskCopyDirTo::SessionTaskCopyDirTo(GuestSession *pSession, 632 1098 const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter, … … 638 1104 , mDirCopyFlags(enmDirCopyFlags) 639 1105 { 640 m_strTaskName = "gctlC opyDirTo";1106 m_strTaskName = "gctlCpyDirTo"; 641 1107 } 642 1108 … … 761 1227 Utf8Str strSrcFile = strSrcDir + strSrcSubDir + Utf8Str(pDirEntry->szName); 762 1228 Utf8Str strDstFile = strDstDir + strSrcSubDir + Utf8Str(pDirEntry->szName); 763 rc = fileCopyTo Guest(strSrcFile, strDstFile, FileCopyFlag_None);1229 rc = fileCopyTo(strSrcFile, strDstFile, FileCopyFlag_None); 764 1230 } 765 1231 break; … … 817 1283 818 1284 SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession, 819 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)820 : GuestSessionTask(pSession) ,821 mSource(strSource),822 mSourceFile(NULL),823 mSourceOffset(0),824 mSourceSize(0),825 826 { 827 mCopyFileFlags = uFlags; 828 m_strTaskName = "gctlC opyFileTo";1285 const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags) 1286 : GuestSessionTask(pSession) 1287 , mSource(strSource) 1288 , mSourceFile(NULL) 1289 , mSourceOffset(0) 1290 , mSourceSize(0) 1291 , mDest(strDest) 1292 , mFileCopyFlags(enmFileCopyFlags) 1293 { 1294 m_strTaskName = "gctlCpyFileTo"; 829 1295 } 830 1296 831 1297 SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession, 832 1298 PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize, 833 const Utf8Str &strDest, uint32_t uFlags)1299 const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags) 834 1300 : GuestSessionTask(pSession) 835 { 836 mSourceFile = pSourceFile;837 mSourceOffset = cbSourceOffset;838 mSourceSize = cbSourceSize;839 mDest = strDest;840 mCopyFileFlags = uFlags; 841 m_strTaskName = "gctlC opyFileToWithHandle";1301 , mSourceFile(pSourceFile) 1302 , mSourceOffset(cbSourceOffset) 1303 , mSourceSize(cbSourceSize) 1304 , mDest(strDest) 1305 , mFileCopyFlags(enmFileCopyFlags) 1306 { 1307 m_strTaskName = "gctlCpyFileToH"; 842 1308 } 843 1309 … … 875 1341 } 876 1342 877 if (m CopyFileFlags)1343 if (mFileCopyFlags) 878 1344 { 879 1345 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 880 1346 Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"), 881 m CopyFileFlags));1347 mFileCopyFlags)); 882 1348 return VERR_NOT_IMPLEMENTED; 883 1349 } … … 931 1397 { 932 1398 if (mSourceFile) /* Use existing file handle. */ 933 rc = fileCopyTo GuestEx(mSource, mDest, (FileCopyFlag_T)mCopyFileFlags, mSourceFile, mSourceOffset, mSourceSize);1399 rc = fileCopyToEx(mSource, mDest, (FileCopyFlag_T)mFileCopyFlags, mSourceFile, mSourceOffset, mSourceSize); 934 1400 else 935 rc = fileCopyTo Guest(mSource, mDest, (FileCopyFlag_T)mCopyFileFlags);1401 rc = fileCopyTo(mSource, mDest, (FileCopyFlag_T)mFileCopyFlags); 936 1402 937 1403 if (RT_SUCCESS(rc)) … … 944 1410 945 1411 SessionTaskCopyFileFrom::SessionTaskCopyFileFrom(GuestSession *pSession, 946 const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)1412 const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags) 947 1413 : GuestSessionTask(pSession) 948 { 949 mSource = strSource;950 mDest = strDest;951 mFlags = uFlags; 952 m_strTaskName = "gctlC opyFileFrom";1414 , mSource(strSource) 1415 , mDest(strDest) 1416 , mFileCopyFlags(enmFileCopyFlags) 1417 { 1418 m_strTaskName = "gctlCpyFileFrm"; 953 1419 } 954 1420 … … 965 1431 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 966 1432 967 RTMSINTERVAL msTimeout = 30 * 1000; /** @todo 30s timeout for all actions. Make this configurable? */ 968 969 /* 970 * Note: There will be races between querying file size + reading the guest file's 971 * content because we currently *do not* lock down the guest file when doing the 972 * actual operations. 973 ** @todo Use the IGuestFile API for locking down the file on the guest! 974 */ 975 GuestFsObjData objData; 976 int rcGuest = VERR_IPE_UNINITIALIZED_STATUS; 977 int rc = mSession->i_fileQueryInfoInternal(Utf8Str(mSource), false /*fFollowSymlinks*/, objData, &rcGuest); 978 if (RT_FAILURE(rc)) 979 { 980 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 981 Utf8StrFmt(GuestSession::tr("Querying guest file information for \"%s\" failed: %Rrc"), 982 mSource.c_str(), rc)); 983 } 984 else if (objData.mType != FsObjType_File) /* Only single files are supported at the moment. */ 985 { 986 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 987 Utf8StrFmt(GuestSession::tr("Object \"%s\" on the guest is not a file"), mSource.c_str())); 988 rc = VERR_NOT_A_FILE; 989 } 990 1433 int rc = fileCopyFrom(mSource, mDest, mFileCopyFlags); 991 1434 if (RT_SUCCESS(rc)) 992 { 993 RTFILE fileDest; 994 rc = RTFileOpen(&fileDest, mDest.c_str(), 995 RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */ 996 if (RT_FAILURE(rc)) 997 { 998 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 999 Utf8StrFmt(GuestSession::tr("Opening/creating destination file on host \"%s\" failed: %Rrc"), 1000 mDest.c_str(), rc)); 1001 } 1002 else 1003 { 1004 GuestProcessStartupInfo procInfo; 1005 procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"), 1006 mSource.c_str(), mDest.c_str(), objData.mObjectSize); 1007 procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT); 1008 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut; 1009 1010 /* Set arguments.*/ 1011 procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */ 1012 procInfo.mArguments.push_back(mSource); /* Which file to output? */ 1013 1014 /* Startup process. */ 1015 ComObjPtr<GuestProcess> pProcess; 1016 rc = mSession->i_processCreateExInternal(procInfo, pProcess); 1017 if (RT_SUCCESS(rc)) 1018 rc = pProcess->i_startProcess(msTimeout, &rcGuest); 1019 if (RT_FAILURE(rc)) 1020 { 1021 switch (rc) 1022 { 1023 case VERR_GSTCTL_GUEST_ERROR: 1024 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 1025 break; 1026 1027 default: 1028 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1029 Utf8StrFmt(GuestSession::tr( 1030 "Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 1031 mSource.c_str(), rc)); 1032 break; 1033 } 1034 } 1035 else 1036 { 1037 ProcessWaitResult_T waitRes; 1038 BYTE byBuf[_64K]; 1039 1040 BOOL fCanceled = FALSE; 1041 uint64_t cbWrittenTotal = 0; 1042 uint64_t cbToRead = objData.mObjectSize; 1043 1044 for (;;) 1045 { 1046 rc = pProcess->i_waitFor(ProcessWaitForFlag_StdOut, msTimeout, waitRes, &rcGuest); 1047 if (RT_FAILURE(rc)) 1048 { 1049 switch (rc) 1050 { 1051 case VERR_GSTCTL_GUEST_ERROR: 1052 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 1053 break; 1054 1055 default: 1056 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1057 Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"), 1058 mSource.c_str(), rc)); 1059 break; 1060 } 1061 1062 break; 1063 } 1064 1065 if ( waitRes == ProcessWaitResult_StdOut 1066 || waitRes == ProcessWaitResult_WaitFlagNotSupported) 1067 { 1068 /* If the guest does not support waiting for stdin, we now yield in 1069 * order to reduce the CPU load due to busy waiting. */ 1070 if (waitRes == ProcessWaitResult_WaitFlagNotSupported) 1071 RTThreadYield(); /* Optional, don't check rc. */ 1072 1073 uint32_t cbRead = 0; /* readData can return with VWRN_GSTCTL_OBJECTSTATE_CHANGED. */ 1074 rc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf), 1075 msTimeout, byBuf, sizeof(byBuf), 1076 &cbRead, &rcGuest); 1077 if (RT_FAILURE(rc)) 1078 { 1079 switch (rc) 1080 { 1081 case VERR_GSTCTL_GUEST_ERROR: 1082 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest)); 1083 break; 1084 1085 default: 1086 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1087 Utf8StrFmt(GuestSession::tr("Reading from guest file \"%s\" (offset %RU64) failed: %Rrc"), 1088 mSource.c_str(), cbWrittenTotal, rc)); 1089 break; 1090 } 1091 1092 break; 1093 } 1094 1095 if (cbRead) 1096 { 1097 rc = RTFileWrite(fileDest, byBuf, cbRead, NULL /* No partial writes */); 1098 if (RT_FAILURE(rc)) 1099 { 1100 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1101 Utf8StrFmt(GuestSession::tr("Writing to host file \"%s\" (%RU64 bytes left) failed: %Rrc"), 1102 mDest.c_str(), cbToRead, rc)); 1103 break; 1104 } 1105 1106 /* Only subtract bytes reported written by the guest. */ 1107 Assert(cbToRead >= cbRead); 1108 cbToRead -= cbRead; 1109 1110 /* Update total bytes written to the guest. */ 1111 cbWrittenTotal += cbRead; 1112 Assert(cbWrittenTotal <= (uint64_t)objData.mObjectSize); 1113 1114 /* Did the user cancel the operation above? */ 1115 if ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled))) 1116 && fCanceled) 1117 break; 1118 1119 rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)objData.mObjectSize / 100.0))); 1120 if (RT_FAILURE(rc)) 1121 break; 1122 } 1123 } 1124 else 1125 { 1126 break; 1127 } 1128 1129 } /* for */ 1130 1131 LogFlowThisFunc(("rc=%Rrc, rcGuest=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n", 1132 rc, rcGuest, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead)); 1133 1134 /* 1135 * Wait on termination of guest process until it completed all operations. 1136 */ 1137 if ( !fCanceled 1138 || RT_SUCCESS(rc)) 1139 { 1140 rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &rcGuest); 1141 if ( RT_FAILURE(rc) 1142 || waitRes != ProcessWaitResult_Terminate) 1143 { 1144 if (RT_FAILURE(rc)) 1145 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1146 Utf8StrFmt( 1147 GuestSession::tr("Waiting on termination for copying file \"%s\" from guest failed: %Rrc"), 1148 mSource.c_str(), rc)); 1149 else 1150 { 1151 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1152 Utf8StrFmt(GuestSession::tr( 1153 "Waiting on termination for copying file \"%s\" from guest failed with wait result %ld"), 1154 mSource.c_str(), waitRes)); 1155 rc = VERR_GENERAL_FAILURE; /* Fudge. */ 1156 } 1157 } 1158 } 1159 1160 if (RT_SUCCESS(rc)) 1161 { 1162 /** @todo this code sequence is duplicated in CopyTo */ 1163 ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally; 1164 HRESULT hrc = pProcess->COMGETTER(Status(&procStatus)); 1165 if (!SUCCEEDED(hrc)) 1166 procStatus = ProcessStatus_TerminatedAbnormally; 1167 1168 LONG exitCode = 42424242; 1169 hrc = pProcess->COMGETTER(ExitCode(&exitCode)); 1170 if (!SUCCEEDED(hrc)) 1171 exitCode = 42424242; 1172 1173 if ( procStatus != ProcessStatus_TerminatedNormally 1174 || exitCode != 0) 1175 { 1176 LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode)); 1177 if (procStatus == ProcessStatus_TerminatedNormally) 1178 rc = GuestProcessTool::i_exitCodeToRc(procInfo, exitCode); 1179 else 1180 rc = VERR_GENERAL_FAILURE; 1181 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1182 Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to host failed: %Rrc"), 1183 mSource.c_str(), rc)); 1184 } 1185 /* 1186 * Even if we succeeded until here make sure to check whether we really transfered 1187 * everything. 1188 */ 1189 else if ( objData.mObjectSize > 0 1190 && cbWrittenTotal == 0) 1191 { 1192 /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write 1193 * to the destination -> access denied. */ 1194 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1195 Utf8StrFmt(GuestSession::tr("Writing guest file \"%s\" to host to \"%s\" failed: Access denied"), 1196 mSource.c_str(), mDest.c_str())); 1197 rc = VERR_ACCESS_DENIED; 1198 } 1199 else if (cbWrittenTotal < (uint64_t)objData.mObjectSize) 1200 { 1201 /* If we did not copy all let the user know. */ 1202 setProgressErrorMsg(VBOX_E_IPRT_ERROR, 1203 Utf8StrFmt(GuestSession::tr("Copying guest file \"%s\" to host to \"%s\" failed (%RU64/%RI64 bytes transfered)"), 1204 mSource.c_str(), mDest.c_str(), cbWrittenTotal, objData.mObjectSize)); 1205 rc = VERR_INTERRUPTED; 1206 } 1207 else 1208 rc = setProgressSuccess(); 1209 } 1210 } 1211 1212 RTFileClose(fileDest); 1213 } 1214 } 1435 rc = setProgressSuccess(); 1215 1436 1216 1437 LogFlowFuncLeaveRC(rc);
Note:
See TracChangeset
for help on using the changeset viewer.