Changeset 85371 in vbox for trunk/src/VBox/Main/src-client
- Timestamp:
- Jul 17, 2020 10:02:58 AM (5 years ago)
- Location:
- trunk/src/VBox/Main/src-client
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
r82968 r85371 939 939 /* cbDataAdd is optional. */ 940 940 941 LogFlowFunc(("cb Total=%RU64, cbProcessed=%RU64, cbRemaining=%RU64, cbDataAdd=%RU32\n",942 pData-> getTotal(), pData->getProcessed(), pData->getRemaining(), cbDataAdd));941 LogFlowFunc(("cbExtra=%RU64, cbProcessed=%RU64, cbRemaining=%RU64, cbDataAdd=%RU32\n", 942 pData->cbExtra, pData->cbProcessed, pData->getRemaining(), cbDataAdd)); 943 943 944 944 if (!pResp) -
trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
r85020 r85371 420 420 LogFlowThisFunc(("cTransfersPending=%RU32\n", mDataBase.m_cTransfersPending)); 421 421 422 /* Don't allow receiving the actual data until our transfer actuallyis complete. */422 /* Don't allow receiving the actual data until our current transfer is complete. */ 423 423 if (mDataBase.m_cTransfersPending) 424 424 return setError(E_FAIL, tr("Current drop operation still in progress")); 425 425 426 GuestDnDRecvCtx *pCtx = &mData.mRecvCtx;427 426 HRESULT hr = S_OK; 428 427 429 428 try 430 429 { 431 bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length()); 432 if (fHasURIList) 433 { 434 LogRel2(("DnD: Drop directory is: %s\n", pCtx->mURI.getDroppedFiles().GetDirAbs())); 435 int rc2 = pCtx->mURI.toMetaData(aData); 436 if (RT_FAILURE(rc2)) 437 hr = E_OUTOFMEMORY; 430 GuestDnDRecvCtx *pCtx = &mData.mRecvCtx; 431 if (DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length())) 432 { 433 PDNDDROPPEDFILES pDF = &pCtx->mTransfer.mDroppedFiles; 434 435 const char *pcszDropDirAbs = DnDDroppedFilesGetDirAbs(pDF); 436 AssertPtr(pcszDropDirAbs); 437 438 LogRel2(("DnD: Using drop directory '%s'\n", pcszDropDirAbs)); 439 440 char *pszBuf; 441 size_t cbBuf; 442 int rc = DnDTransferListGetRootsEx(&pCtx->mTransfer.mList, DNDTRANSFERLISTFMT_NATIVE, 443 pcszDropDirAbs, "\n" /* On all platforms */, &pszBuf, &cbBuf); 444 if (RT_SUCCESS(rc)) 445 { 446 aData.resize(cbBuf); 447 memcpy(&aData.front(), pszBuf, cbBuf); 448 RTStrFree(pszBuf); 449 } 450 else 451 LogRel(("DnD: Unable to build source root list, rc=%Rrc\n", rc)); 438 452 } 439 453 else 440 454 { 441 const size_t cbData = pCtx->mData.getMeta().getSize(); 442 LogFlowFunc(("cbData=%zu\n", cbData)); 443 if (cbData) 455 if (pCtx->Meta.cbData) 444 456 { 445 457 /* Copy the data into a safe array of bytes. */ 446 aData.resize( cbData);447 memcpy(&aData.front(), pCtx-> mData.getMeta().getData(),cbData);458 aData.resize(pCtx->Meta.cbData); 459 memcpy(&aData.front(), pCtx->Meta.pvData, pCtx->Meta.cbData); 448 460 } 449 461 else … … 541 553 542 554 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 555 /** 556 * Handles receiving a send data header from the guest. 557 * 558 * @returns VBox status code. 559 * @param pCtx Receive context to use. 560 * @param pDataHdr Pointer to send data header from the guest. 561 */ 543 562 int GuestDnDSource::i_onReceiveDataHdr(GuestDnDRecvCtx *pCtx, PVBOXDNDSNDDATAHDR pDataHdr) 544 563 { 545 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 546 AssertReturn(pDataHdr, VERR_INVALID_POINTER); 547 548 pCtx->mData.setEstimatedSize(pDataHdr->cbTotal, pDataHdr->cbMeta); 549 550 Assert(pCtx->mURI.getObjToProcess() == 0); 551 pCtx->mURI.reset(); 552 pCtx->mURI.setEstimatedObjects(pDataHdr->cObjects); 564 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 565 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER); 566 567 LogRel2(("DnD: Receiving %RU64 bytes total data (%RU64 bytes meta data, %RU64 objects) from guest ...\n", 568 pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects)); 569 570 AssertReturn(pDataHdr->cbTotal >= pDataHdr->cbMeta, VERR_INVALID_PARAMETER); 571 572 int rc = pCtx->Meta.resize(pDataHdr->cbMeta); 573 AssertRCReturn(rc, rc); 574 575 pCtx->cbExtra = pDataHdr->cbTotal - pDataHdr->cbMeta; 576 577 Assert(pCtx->mTransfer.cObjToProcess == 0); /* Sanity. */ 578 Assert(pCtx->mTransfer.cObjProcessed == 0); 579 580 pCtx->mTransfer.reset(); 581 582 pCtx->mTransfer.cObjToProcess = pDataHdr->cObjects; 553 583 554 584 /** @todo Handle compression type. */ … … 559 589 } 560 590 591 /** 592 * Handles receiving a send data block from the guest. 593 * 594 * @returns VBox status code. 595 * @param pCtx Receive context to use. 596 * @param pSndData Pointer to send data block from the guest. 597 */ 561 598 int GuestDnDSource::i_onReceiveData(GuestDnDRecvCtx *pCtx, PVBOXDNDSNDDATA pSndData) 562 599 { … … 568 605 try 569 606 { 570 GuestDnDData *pData = &pCtx->mData; 571 GuestDnDURIData *pURI = &pCtx->mURI; 607 GuestDnDTransferRecvData *pTransfer = &pCtx->mTransfer; 572 608 573 609 uint32_t cbData; … … 593 629 pvData = pSndData->u.v3.pvData; 594 630 595 /* Note: Data sizes get updated in i_onReceiveDataHdr(). */596 cbTotal = pData->getTotal();597 cb Meta = pData->getMeta().getSize();598 }599 Assert(cbTotal);631 /* Note: Data sizes get initialized in i_onReceiveDataHdr(). 632 * So just use the set values here. */ 633 cbTotal = pCtx->getTotal(); 634 cbMeta = pCtx->Meta.cbData; 635 } 600 636 601 637 if ( cbData == 0 602 || cbData > 603 { 604 LogFlowFunc(("Incoming data size invalid: cbData=%RU32, cbToProcess=%RU64\n", cbData, pData->getTotal()));638 || cbData > cbTotal /* Paranoia */) 639 { 640 LogFlowFunc(("Incoming data size invalid: cbData=%RU32, cbToProcess=%RU64\n", cbData, cbTotal)); 605 641 rc = VERR_INVALID_PARAMETER; 606 642 } 607 else if (cbTotal < cbMeta) 643 else if ( cbTotal == 0 644 || cbTotal < cbMeta) 608 645 { 609 646 AssertMsgFailed(("cbTotal (%RU64) is smaller than cbMeta (%RU32)\n", cbTotal, cbMeta)); … … 611 648 } 612 649 613 if (RT_SUCCESS(rc)) 614 { 615 cbMeta = pData->getMeta().add(pvData, cbData); 616 LogFlowThisFunc(("cbMetaSize=%zu, cbData=%RU32, cbMeta=%RU32, cbTotal=%RU64\n", 617 pData->getMeta().getSize(), cbData, cbMeta, cbTotal)); 618 } 619 620 if (RT_SUCCESS(rc)) 621 { 622 /* 623 * (Meta) Data transfer complete? 624 */ 625 Assert(cbMeta <= pData->getMeta().getSize()); 626 if (cbMeta == pData->getMeta().getSize()) 650 if (RT_FAILURE(rc)) 651 return rc; 652 653 cbMeta = pCtx->Meta.add(pvData, cbData); 654 655 LogFlowThisFunc(("cbData=%RU32, cbMeta=%RU32, cbTotal=%RU64\n", cbData, cbMeta, cbTotal)); 656 657 /* 658 * (Meta) Data transfer complete? 659 */ 660 Assert(cbMeta <= pCtx->Meta.cbAllocated); 661 if (cbMeta == pCtx->Meta.cbAllocated) 662 { 663 LogRel2(("DnD: Receiving meta data complete\n")); 664 665 if (DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length())) 627 666 { 628 bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length()); 629 LogFlowThisFunc(("fHasURIList=%RTbool\n", fHasURIList)); 630 if (fHasURIList) 667 LogRel2(("DnD: Building transfer list from meta data ...\n")); 668 669 rc = DnDTransferListAppendPathsFromBuffer(&pTransfer->mList, DNDTRANSFERLISTFMT_URI, 670 (const char *)pCtx->Meta.pvData, pCtx->Meta.cbData, DND_PATH_SEPARATOR, 671 DNDTRANSFERLIST_FLAGS_NONE); 672 /* Validation. */ 673 if (RT_SUCCESS(rc)) 631 674 { 632 /* Try parsing the data as URI list. */ 633 rc = pURI->fromRemoteMetaData(pData->getMeta()); 634 if (RT_SUCCESS(rc)) 635 { 636 if (mDataBase.m_uProtocolVersion < 3) 637 pData->setEstimatedSize(cbTotal, cbMeta); 638 639 /* 640 * Update our process with the data we already received. 641 * Note: The total size will consist of the meta data (in pVecData) and 642 * the actual accumulated file/directory data from the guest. 643 */ 644 rc = updateProgress(pData, pCtx->mpResp, (uint32_t)pData->getMeta().getSize()); 645 } 675 uint64_t cRoots = DnDTransferListGetRootCount(&pTransfer->mList); 676 if ( cRoots == 0 677 || cRoots > pTransfer->cObjToProcess) 678 rc = VERR_INVALID_PARAMETER; 646 679 } 647 else /* Raw data. */ 648 rc = updateProgress(pData, pCtx->mpResp, cbData); 680 681 if (RT_SUCCESS(rc)) 682 { 683 /* Update our process with the data we already received. */ 684 rc = updateProgress(pCtx, pCtx->mpResp, cbMeta); 685 AssertRC(rc); 686 } 687 688 if (RT_FAILURE(rc)) 689 LogRel(("DnD: Error building transfer list, rc=%Rrc\n", rc)); 649 690 } 691 else /* Raw data. */ 692 { 693 rc = updateProgress(pCtx, pCtx->mpResp, cbData); 694 AssertRC(rc); 695 } 696 697 if (RT_FAILURE(rc)) 698 LogRel(("DnD: Error receiving meta data, rc=%Rrc\n", rc)); 650 699 } 651 700 } … … 667 716 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", pszPath, cbPath, fMode)); 668 717 669 /* 670 * Sanity checking. 671 */ 672 if ( !cbPath 673 || cbPath > RTPATH_MAX) 674 { 675 LogFlowFunc(("Path length invalid, bailing out\n")); 676 return VERR_INVALID_PARAMETER; 677 } 678 679 int rc = RTStrValidateEncodingEx(pszPath, RTSTR_MAX, 0); 718 AssertMsgReturn(pCtx->isComplete() == false, 719 ("Data transfer already complete, bailing out\n"), VERR_INVALID_PARAMETER); 720 721 const PDNDTRANSFEROBJECT pObj = &pCtx->mTransfer.mObj; 722 const PDNDDROPPEDFILES pDF = &pCtx->mTransfer.mDroppedFiles; 723 724 int rc = DnDTransferObjectInit(pObj, DNDTRANSFEROBJTYPE_DIRECTORY, 725 DnDDroppedFilesGetDirAbs(pDF), pszPath); 726 if (RT_SUCCESS(rc)) 727 { 728 const char *pcszPathAbs = DnDTransferObjectGetSourcePath(pObj); 729 AssertPtr(pcszPathAbs); 730 731 rc = RTDirCreateFullPath(pcszPathAbs, fMode); 732 if (RT_SUCCESS(rc)) 733 { 734 pCtx->mTransfer.cObjProcessed++; 735 if (pCtx->mTransfer.cObjProcessed <= pCtx->mTransfer.cObjToProcess) 736 { 737 rc = DnDDroppedFilesAddDir(pDF, pcszPathAbs); 738 } 739 else 740 rc = VERR_TOO_MUCH_DATA; 741 742 DnDTransferObjectDestroy(pObj); 743 744 if (RT_SUCCESS(rc)) 745 LogRel2(("DnD: Created guest directory '%s' on host\n", pcszPathAbs)); 746 } 747 else 748 LogRel(("DnD: Error creating guest directory '%s' on host, rc=%Rrc\n", pcszPathAbs, rc)); 749 } 750 680 751 if (RT_FAILURE(rc)) 681 { 682 LogFlowFunc(("Path validation failed with %Rrc, bailing out\n", rc)); 683 return VERR_INVALID_PARAMETER; 684 } 685 686 if (pCtx->mURI.isComplete()) 687 { 688 LogFlowFunc(("Data transfer already complete, bailing out\n")); 689 return VERR_INVALID_PARAMETER; 690 } 691 692 GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */ 693 694 rc = objCtx.createIntermediate(DnDURIObject::Type_Directory); 695 if (RT_FAILURE(rc)) 696 return rc; 697 698 DnDURIObject *pObj = objCtx.getObj(); 699 AssertPtr(pObj); 700 701 const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs(); 702 char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath); 703 if (pszDir) 704 { 705 #ifdef RT_OS_WINDOWS 706 RTPathChangeToDosSlashes(pszDir, true /* fForce */); 707 #else 708 RTPathChangeToDosSlashes(pszDir, true /* fForce */); 709 #endif 710 rc = RTDirCreateFullPath(pszDir, fMode); 711 if (RT_SUCCESS(rc)) 712 { 713 pCtx->mURI.processObject(*pObj); 714 715 /* Add for having a proper rollback. */ 716 int rc2 = pCtx->mURI.getDroppedFiles().AddDir(pszDir); 717 AssertRC(rc2); 718 719 objCtx.reset(); 720 LogRel2(("DnD: Created guest directory '%s' on host\n", pszDir)); 721 } 722 else 723 LogRel(("DnD: Error creating guest directory '%s' on host, rc=%Rrc\n", pszDir, rc)); 724 725 RTStrFree(pszDir); 726 } 727 else 728 rc = VERR_NO_MEMORY; 752 LogRel(("DnD: Receiving guest directory '%s' failed with rc=%Rrc\n", pszPath, rc)); 729 753 730 754 LogFlowFuncLeaveRC(rc); … … 732 756 } 733 757 758 /** 759 * Receives a file header from the guest. 760 * 761 * @returns VBox status code. 762 * @param pCtx Receive context to use. 763 * @param pszPath File path of file to use. 764 * @param cbPath Size (in bytes, including terminator) of file path. 765 * @param cbSize File size (in bytes) to receive. 766 * @param fMode File mode to use. 767 * @param fFlags Additional receive flags; not used yet. 768 */ 734 769 int GuestDnDSource::i_onReceiveFileHdr(GuestDnDRecvCtx *pCtx, const char *pszPath, uint32_t cbPath, 735 770 uint64_t cbSize, uint32_t fMode, uint32_t fFlags) 736 771 { 737 RT_NOREF(fFlags);738 772 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 739 773 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); … … 742 776 /* fFlags are optional. */ 743 777 778 RT_NOREF(fFlags); 779 744 780 LogFlowFunc(("pszPath=%s, cbPath=%RU32, cbSize=%RU64, fMode=0x%x, fFlags=0x%x\n", pszPath, cbPath, cbSize, fMode, fFlags)); 745 781 746 /* 747 * Sanity checking. 748 */ 749 if ( !cbPath 750 || cbPath > RTPATH_MAX) 751 { 752 return VERR_INVALID_PARAMETER; 753 } 754 755 if (!RTStrIsValidEncoding(pszPath)) 756 return VERR_INVALID_PARAMETER; 757 758 if (cbSize > pCtx->mData.getTotal()) 759 { 760 AssertMsgFailed(("File size (%RU64) exceeds total size to transfer (%RU64)\n", cbSize, pCtx->mData.getTotal())); 761 return VERR_INVALID_PARAMETER; 762 } 763 764 if (pCtx->mURI.getObjToProcess() && pCtx->mURI.isComplete()) 765 return VERR_INVALID_PARAMETER; 782 AssertMsgReturn(cbSize <= pCtx->cbExtra, 783 ("File size (%RU64) exceeds extra size to transfer (%RU64)\n", cbSize, pCtx->cbExtra), VERR_INVALID_PARAMETER); 784 AssertMsgReturn( pCtx->isComplete() == false 785 && pCtx->mTransfer.cObjToProcess, 786 ("Data transfer already complete, bailing out\n"), VERR_INVALID_PARAMETER); 766 787 767 788 int rc = VINF_SUCCESS; … … 769 790 do 770 791 { 771 GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */ 772 DnDURIObject *pObj = objCtx.getObj(); 773 774 /* 775 * Sanity checking. 776 */ 777 if (pObj) 778 { 779 if ( pObj->IsOpen() 780 && !pObj->IsComplete()) 792 const PDNDTRANSFEROBJECT pObj = &pCtx->mTransfer.mObj; 793 794 if ( DnDTransferObjectIsOpen(pObj) 795 && !DnDTransferObjectIsComplete(pObj)) 796 { 797 AssertMsgFailed(("Object '%s' not complete yet\n", DnDTransferObjectGetSourcePath(pObj))); 798 rc = VERR_WRONG_ORDER; 799 break; 800 } 801 802 const PDNDDROPPEDFILES pDF = &pCtx->mTransfer.mDroppedFiles; 803 804 rc = DnDTransferObjectInit(pObj, DNDTRANSFEROBJTYPE_FILE, DnDDroppedFilesGetDirAbs(pDF), pszPath); 805 AssertRCBreak(rc); 806 807 const char *pcszSource = DnDTransferObjectGetSourcePath(pObj); 808 AssertPtrBreakStmt(pcszSource, VERR_INVALID_POINTER); 809 810 /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */ 811 rc = DnDTransferObjectOpen(pObj, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE, 812 (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR, DNDTRANSFEROBJECT_FLAGS_NONE); 813 if (RT_FAILURE(rc)) 814 { 815 LogRel(("DnD: Error opening/creating guest file '%s' on host, rc=%Rrc\n", pcszSource, rc)); 816 break; 817 } 818 819 /* Note: Protocol v1 does not send any file sizes, so always 0. */ 820 if (mDataBase.m_uProtocolVersion >= 2) 821 rc = DnDTransferObjectSetSize(pObj, cbSize); 822 823 /** @todo Unescape path before printing. */ 824 LogRel2(("DnD: Transferring guest file '%s' to host (%RU64 bytes, mode %#x)\n", 825 pcszSource, DnDTransferObjectGetSize(pObj), DnDTransferObjectGetMode(pObj))); 826 827 /** @todo Set progress object title to current file being transferred? */ 828 829 if (DnDTransferObjectIsComplete(pObj)) /* 0-byte file? We're done already. */ 830 { 831 LogRel2(("DnD: Transferring guest file '%s' (0 bytes) to host complete\n", pcszSource)); 832 833 pCtx->mTransfer.cObjProcessed++; 834 if (pCtx->mTransfer.cObjProcessed <= pCtx->mTransfer.cObjToProcess) 781 835 { 782 AssertMsgFailed(("Object '%s' not complete yet\n", pObj->GetPath().c_str())); 783 rc = VERR_WRONG_ORDER; 784 break; 836 /* Add for having a proper rollback. */ 837 rc = DnDDroppedFilesAddFile(pDF, pcszSource); 785 838 } 786 787 if (pObj->IsOpen()) /* File already opened? */ 788 { 789 AssertMsgFailed(("Current opened object is '%s', close this first\n", pObj->GetPath().c_str())); 790 rc = VERR_WRONG_ORDER; 791 break; 792 } 793 } 794 else 795 { 796 /* 797 * Create new intermediate object to work with. 798 */ 799 rc = objCtx.createIntermediate(DnDURIObject::Type_File); 800 } 801 802 if (RT_SUCCESS(rc)) 803 { 804 pObj = objCtx.getObj(); 805 AssertPtr(pObj); 806 807 const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs(); 808 AssertPtr(pszDroppedFilesDir); 809 810 char pszPathAbs[RTPATH_MAX]; 811 rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszDroppedFilesDir, pszPath); 812 if (RT_FAILURE(rc)) 813 { 814 LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc)); 815 break; 816 } 817 818 rc = pObj->Init(DnDURIObject::Type_File, pszPathAbs); 819 if (RT_SUCCESS(rc)) 820 { 821 /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */ 822 rc = pObj->Open(RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE, 823 (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); 824 if (RT_SUCCESS(rc)) 825 { 826 /* Add for having a proper rollback. */ 827 int rc2 = pCtx->mURI.getDroppedFiles().AddFile(pszPathAbs); 828 AssertRC(rc2); 829 } 830 } 831 832 if (RT_FAILURE(rc)) 833 LogRel(("DnD: Error opening/creating guest file '%s' on host, rc=%Rrc\n", pszPathAbs, rc)); 834 } 835 836 if (RT_SUCCESS(rc)) 837 { 838 /* Note: Protocol v1 does not send any file sizes, so always 0. */ 839 if (mDataBase.m_uProtocolVersion >= 2) 840 rc = pObj->SetSize(cbSize); 841 842 /** @todo Unescape path before printing. */ 843 LogRel2(("DnD: Transferring guest file '%s' to host (%RU64 bytes, mode 0x%x)\n", 844 pObj->GetPath().c_str(), pObj->GetSize(), pObj->GetMode())); 845 846 /** @todo Set progress object title to current file being transferred? */ 847 848 if (pObj->IsComplete()) /* 0-byte file? We're done already. */ 849 { 850 LogRel2(("DnD: Transferring guest file '%s' (0 bytes) to host complete\n", pObj->GetPath().c_str())); 851 852 pCtx->mURI.processObject(*pObj); 853 pObj->Close(); 854 855 objCtx.reset(); 856 } 839 else 840 rc = VERR_TOO_MUCH_DATA; 841 842 DnDTransferObjectDestroy(pObj); 857 843 } 858 844 … … 884 870 do 885 871 { 886 GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */887 DnDURIObject *pObj = objCtx.getObj(); 888 889 if (!pObj)890 { 891 LogFlowFunc(("Warning: No current object set\n"));872 const PDNDTRANSFEROBJECT pObj = &pCtx->mTransfer.mObj; 873 874 if ( DnDTransferObjectIsOpen(pObj) 875 && !DnDTransferObjectIsComplete(pObj)) 876 { 877 AssertMsgFailed(("Object '%s' not complete yet\n", DnDTransferObjectGetSourcePath(pObj))); 892 878 rc = VERR_WRONG_ORDER; 893 879 break; 894 880 } 895 881 896 if (pObj->IsComplete()) 897 { 898 LogFlowFunc(("Warning: Object '%s' already completed\n", pObj->GetPath().c_str())); 899 rc = VERR_WRONG_ORDER; 900 break; 901 } 902 903 if (!pObj->IsOpen()) /* File opened on host? */ 904 { 905 LogFlowFunc(("Warning: Object '%s' not opened\n", pObj->GetPath().c_str())); 906 rc = VERR_WRONG_ORDER; 907 break; 908 } 882 const char *pcszSource = DnDTransferObjectGetSourcePath(pObj); 883 AssertPtrBreakStmt(pcszSource, VERR_INVALID_POINTER); 909 884 910 885 uint32_t cbWritten; 911 rc = pObj->Write(pvData, cbData, &cbWritten); 912 if (RT_SUCCESS(rc)) 913 { 914 Assert(cbWritten <= cbData); 915 if (cbWritten < cbData) 916 { 917 LogRel(("DnD: Only written %RU32 of %RU32 bytes of guest file '%s' -- disk full?\n", 918 cbWritten, cbData, pObj->GetPath().c_str())); 919 rc = VERR_IO_GEN_FAILURE; /** @todo Find a better rc. */ 920 } 921 922 if (RT_SUCCESS(rc)) 923 rc = updateProgress(&pCtx->mData, pCtx->mpResp, cbWritten); 924 } 925 else 926 LogRel(("DnD: Error writing guest file data for '%s', rc=%Rrc\n", pObj->GetPath().c_str(), rc)); 927 928 if (RT_SUCCESS(rc)) 929 { 930 if (pObj->IsComplete()) 931 { 932 /** @todo Sanitize path. */ 933 LogRel2(("DnD: Transferring guest file '%s' to host complete\n", pObj->GetPath().c_str())); 934 pCtx->mURI.processObject(*pObj); 935 objCtx.reset(); 936 } 886 rc = DnDTransferObjectWrite(pObj, pvData, cbData, &cbWritten); 887 if (RT_FAILURE(rc)) 888 LogRel(("DnD: Error writing guest file data for '%s', rc=%Rrc\n", pcszSource, rc)); 889 890 Assert(cbWritten <= cbData); 891 if (cbWritten < cbData) 892 { 893 LogRel(("DnD: Only written %RU32 of %RU32 bytes of guest file '%s' -- disk full?\n", 894 cbWritten, cbData, pcszSource)); 895 rc = VERR_IO_GEN_FAILURE; /** @todo Find a better rc. */ 896 break; 897 } 898 899 rc = updateProgress(pCtx, pCtx->mpResp, cbWritten); 900 AssertRCBreak(rc); 901 902 if (DnDTransferObjectIsComplete(pObj)) 903 { 904 LogRel2(("DnD: Transferring guest file '%s' to host complete\n", pcszSource)); 905 906 pCtx->mTransfer.cObjProcessed++; 907 if (pCtx->mTransfer.cObjProcessed > pCtx->mTransfer.cObjToProcess) 908 rc = VERR_TOO_MUCH_DATA; 909 910 DnDTransferObjectDestroy(pObj); 937 911 } 938 912 … … 974 948 * Reset any old data. 975 949 */ 976 pCtx-> mData.reset();977 pCtx->m URI.reset();950 pCtx->reset(); 951 pCtx->mTransfer.reset(); 978 952 pResp->reset(); 979 953 … … 1029 1003 if (fURIData) 1030 1004 { 1031 rc = i_receive URIData(pCtx, msTimeout);1005 rc = i_receiveTransferData(pCtx, msTimeout); 1032 1006 } 1033 1007 else … … 1184 1158 } 1185 1159 1186 int GuestDnDSource::i_receive URIData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout)1160 int GuestDnDSource::i_receiveTransferData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout) 1187 1161 { 1188 1162 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 1227 1201 REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_DATA); 1228 1202 1229 DnDDroppedFiles &droppedFiles = pCtx->mURI.getDroppedFiles();1203 const PDNDDROPPEDFILES pDF = &pCtx->mTransfer.mDroppedFiles; 1230 1204 1231 1205 do 1232 1206 { 1233 rc = droppedFiles.OpenTemp(0 /* fFlags */);1207 rc = DnDDroppedFilesOpenTemp(pDF, 0 /* fFlags */); 1234 1208 if (RT_FAILURE(rc)) 1235 1209 { 1236 LogRel(("DnD: Opening dropped files directory '%s' on the host failed with rc=%Rrc\n", droppedFiles.GetDirAbs(), rc)); 1210 LogRel(("DnD: Opening dropped files directory '%s' on the host failed with rc=%Rrc\n", 1211 DnDDroppedFilesGetDirAbs(pDF), rc)); 1237 1212 break; 1238 1213 } 1239 1214 1240 1215 /* 1241 * Receive the URIlist.1216 * Receive the transfer list. 1242 1217 */ 1243 1218 GuestDnDMsg Msg; … … 1282 1257 if (RT_FAILURE(rc)) 1283 1258 { 1284 int rc2 = droppedFiles.Rollback();1259 int rc2 = DnDDroppedFilesRollback(pDF); 1285 1260 if (RT_FAILURE(rc2)) 1286 1261 LogRel(("DnD: Deleting left over temporary files failed (%Rrc), please remove directory '%s' manually\n", 1287 rc2, droppedFiles.GetDirAbs()));1262 rc2, DnDDroppedFilesGetDirAbs(pDF))); 1288 1263 1289 1264 if (rc == VERR_CANCELLED) … … 1310 1285 } 1311 1286 1312 droppedFiles.Close();1287 DnDDroppedFilesClose(pDF); 1313 1288 1314 1289 LogFlowFuncLeaveRC(rc); … … 1429 1404 1430 1405 /* All data processed? */ 1431 if (pCtx-> mData.isComplete())1406 if (pCtx->isComplete()) 1432 1407 fNotify = true; 1433 1408 1434 LogFlowFunc(("cbProcessed=%RU64, cb ToProcess=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",1435 pCtx-> mData.getProcessed(), pCtx->mData.getTotal(), fNotify, rcCallback, rc));1409 LogFlowFunc(("cbProcessed=%RU64, cbExtra=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n", 1410 pCtx->cbProcessed, pCtx->cbExtra, fNotify, rcCallback, rc)); 1436 1411 1437 1412 if (fNotify) … … 1604 1579 1605 1580 /* All data processed? */ 1606 if ( pCtx->m URI.isComplete()1607 && pCtx-> mData.isComplete())1581 if ( pCtx->mTransfer.isComplete() 1582 && pCtx->isComplete()) 1608 1583 { 1609 1584 fNotify = true; 1610 1585 } 1611 1586 1612 LogFlowFunc(("cbProcessed=%RU64, cb ToProcess=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",1613 pCtx-> mData.getProcessed(), pCtx->mData.getTotal(), fNotify, rcCallback, rc));1587 LogFlowFunc(("cbProcessed=%RU64, cbExtra=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n", 1588 pCtx->cbProcessed, pCtx->cbExtra, fNotify, rcCallback, rc)); 1614 1589 1615 1590 if (fNotify) -
trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp
r85020 r85371 563 563 } 564 564 565 /** 566 * Thread handler function for sending data to the guest. 567 * 568 * @param pTask Thread task this handler is associated with. 569 */ 565 570 /* static */ 566 571 void GuestDnDTarget::i_sendDataThreadTask(GuestDnDSendDataTask *pTask) … … 593 598 594 599 /** 595 * Initiates a data transfer from the host to the guest. The source is the host whereas the target is the 596 * guest in this case. 600 * Initiates a data transfer from the host to the guest. 601 * 602 * The source is the host, whereas the target is the guest. 597 603 * 598 604 * @return HRESULT 599 * @param aScreenId 600 * @param aFormat 601 * @param aData 602 * @param aProgress 605 * @param aScreenId Screen ID where this data transfer was initiated from. 606 * @param aFormat Format of data to send. MIME-style. 607 * @param aData Actual data to send. 608 * @param aProgress Where to return the progress object on success. 603 609 */ 604 610 HRESULT GuestDnDTarget::sendData(ULONG aScreenId, const com::Utf8Str &aFormat, const std::vector<BYTE> &aData, … … 632 638 return hr; 633 639 634 GuestDnDSendDataTask *pTask = NULL;635 GuestDnDSendCtx *pSendCtx = NULL;640 GuestDnDSendDataTask *pTask = NULL; 641 GuestDnDSendCtx *pSendCtx = NULL; 636 642 637 643 try 638 644 { 639 / /pSendCtx is passed into SendDataTask where one is deleted in destructor645 /* pSendCtx is passed into SendDataTask where one is deleted in destructor. */ 640 646 pSendCtx = new GuestDnDSendCtx(); 641 pSendCtx->mpTarget = this; 642 pSendCtx->mpResp = pResp; 643 pSendCtx->mScreenID = aScreenId; 644 pSendCtx->mFmtReq = aFormat; 645 pSendCtx->mData.getMeta().add(aData); 647 pSendCtx->mpTarget = this; 648 pSendCtx->mpResp = pResp; 649 pSendCtx->mScreenID = aScreenId; 650 pSendCtx->mFmtReq = aFormat; 651 652 pSendCtx->Meta.add(aData); 646 653 647 654 /* pTask is responsible for deletion of pSendCtx after creating */ … … 757 764 758 765 /** 759 * @returns VBox status code that the caller ignores. Not sure if that's 760 * intentional or not. 766 * Main function for sending DnD host data to the guest. 767 * 768 * @returns VBox status code. 769 * @param pCtx Send context to use. 770 * @param msTimeout Timeout (in ms) to wait for getting the data sent. 761 771 */ 762 772 int GuestDnDTarget::i_sendData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout) … … 776 786 * Note: The decision whether we need to build up a file tree and sending 777 787 * actual file data only depends on the actual formats offered by this target. 778 * If the guest does not want a n URIlist ("text/uri-list") but text ("TEXT" and788 * If the guest does not want a transfer list ("text/uri-list") but text ("TEXT" and 779 789 * friends) instead, still send the data over to the guest -- the file as such still 780 790 * is needed on the guest in this case, as the guest then just wants a simple path 781 * instead of a n URIlist (pointing to a file on the guest itself).791 * instead of a transfer list (pointing to a file on the guest itself). 782 792 * 783 793 ** @todo Support more than one format; add a format<->function handler concept. Later. */ … … 787 797 if (fHasURIList) 788 798 { 789 rc = i_send URIData(pCtx, msTimeout);799 rc = i_sendTransferData(pCtx, msTimeout); 790 800 } 791 801 else … … 800 810 } 801 811 802 int GuestDnDTarget::i_sendDataBody(GuestDnDSendCtx *pCtx, GuestDnDData *pData) 803 { 804 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 805 AssertPtrReturn(pData, VERR_INVALID_POINTER); 812 /** 813 * Sends the common meta data body to the guest. 814 * 815 * @returns VBox status code. 816 * @param pCtx Send context to use. 817 */ 818 int GuestDnDTarget::i_sendMetaDataBody(GuestDnDSendCtx *pCtx) 819 { 820 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 806 821 807 822 /** @todo Add support for multiple HOST_DND_HG_SND_DATA messages in case of more than 64K data! */ 808 if (p Data->getMeta().getSize()> _64K)823 if (pCtx->Meta.cbData > _64K) 809 824 return VERR_NOT_IMPLEMENTED; 810 825 826 const uint32_t cbFmt = (uint32_t)pCtx->Meta.strFmt.length() + 1; /* Include terminator. */ 827 828 LogFlowFunc(("cbFmt=%RU32, cbMeta=%RU32\n", cbFmt, pCtx->Meta.cbData)); 829 811 830 GuestDnDMsg Msg; 812 813 LogFlowFunc(("cbFmt=%RU32, cbMeta=%RU32, cbChksum=%RU32\n",814 pData->getFmtSize(), pData->getMeta().getSize(), pData->getChkSumSize()));815 816 831 Msg.setType(HOST_DND_HG_SND_DATA); 817 832 if (mDataBase.m_uProtocolVersion < 3) 818 833 { 819 Msg.setNextUInt32(pCtx->mScreenID); 820 Msg.setNextPointer(p Data->getFmtMutable(), pData->getFmtSize());/* pvFormat */821 Msg.setNextUInt32( pData->getFmtSize());/* cbFormat */822 Msg.setNextPointer(p Data->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */834 Msg.setNextUInt32(pCtx->mScreenID); /* uScreenId */ 835 Msg.setNextPointer(pCtx->Meta.strFmt.mutableRaw(), cbFmt); /* pvFormat */ 836 Msg.setNextUInt32(cbFmt); /* cbFormat */ 837 Msg.setNextPointer(pCtx->Meta.pvData, (uint32_t)pCtx->Meta.cbData); /* pvData */ 823 838 /* Fill in the current data block size to send. 824 839 * Note: Only supports uint32_t. */ 825 Msg.setNextUInt32((uint32_t)p Data->getMeta().getSize());/* cbData */840 Msg.setNextUInt32((uint32_t)pCtx->Meta.cbData); /* cbData */ 826 841 } 827 842 else 828 843 { 829 844 Msg.setNextUInt32(0); /** @todo ContextID not used yet. */ 830 Msg.setNextPointer(p Data->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */831 Msg.setNextUInt32( pData->getMeta().getSize());/* cbData */832 Msg.setNextPointer( pData->getChkSumMutable(), pData->getChkSumSize());/** @todo pvChecksum; not used yet. */833 Msg.setNextUInt32( pData->getChkSumSize());/** @todo cbChecksum; not used yet. */845 Msg.setNextPointer(pCtx->Meta.pvData, (uint32_t)pCtx->Meta.cbData); /* pvData */ 846 Msg.setNextUInt32((uint32_t)pCtx->Meta.cbData); /* cbData */ 847 Msg.setNextPointer(NULL, 0); /** @todo pvChecksum; not used yet. */ 848 Msg.setNextUInt32(0); /** @todo cbChecksum; not used yet. */ 834 849 } 835 850 836 851 int rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 837 852 if (RT_SUCCESS(rc)) 838 rc = updateProgress(pData, pCtx->mpResp, pData->getMeta().getSize()); 853 { 854 rc = updateProgress(pCtx, pCtx->mpResp, pCtx->Meta.cbData); 855 AssertRC(rc); 856 } 839 857 840 858 LogFlowFuncLeaveRC(rc); … … 842 860 } 843 861 844 int GuestDnDTarget::i_sendDataHeader(GuestDnDSendCtx *pCtx, GuestDnDData *pData, GuestDnDURIData *pURIData /* = NULL */) 845 { 846 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 847 AssertPtrReturn(pData, VERR_INVALID_POINTER); 848 /* pURIData is optional. */ 862 /** 863 * Sends the common meta data header to the guest. 864 * 865 * @returns VBox status code. 866 * @param pCtx Send context to use. 867 */ 868 int GuestDnDTarget::i_sendMetaDataHeader(GuestDnDSendCtx *pCtx) 869 { 870 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 871 872 if (mDataBase.m_uProtocolVersion < 3) /* Protocol < v3 did not support this, skip. */ 873 return VINF_SUCCESS; 849 874 850 875 GuestDnDMsg Msg; … … 855 880 Msg.setNextUInt32(0); /** @todo uFlags; not used yet. */ 856 881 Msg.setNextUInt32(pCtx->mScreenID); /* uScreen */ 857 Msg.setNextUInt64(p Data->getTotal());/* cbTotal */858 Msg.setNextUInt32(p Data->getMeta().getSize());/* cbMeta*/859 Msg.setNextPointer( pData->getFmtMutable(), pData->getFmtSize());/* pvMetaFmt */860 Msg.setNextUInt32( pData->getFmtSize());/* cbMetaFmt */861 Msg.setNextUInt64(p URIData ? pURIData->getObjToProcess() : 0);/* cObjects */882 Msg.setNextUInt64(pCtx->getTotal()); /* cbTotal */ 883 Msg.setNextUInt32(pCtx->Meta.cbData); /* cbMeta*/ 884 Msg.setNextPointer(unconst(pCtx->Meta.strFmt.c_str()), (uint32_t)pCtx->Meta.strFmt.length() + 1); /* pvMetaFmt */ 885 Msg.setNextUInt32((uint32_t)pCtx->Meta.strFmt.length() + 1); /* cbMetaFmt */ 886 Msg.setNextUInt64(pCtx->mTransfer.cObjToProcess ); /* cObjects */ 862 887 Msg.setNextUInt32(0); /** @todo enmCompression; not used yet. */ 863 888 Msg.setNextUInt32(0); /** @todo enmChecksumType; not used yet. */ … … 871 896 } 872 897 873 int GuestDnDTarget::i_sendDirectory(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg) 874 { 875 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 876 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER); 877 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 878 879 DnDURIObject *pObj = pObjCtx->getObj(); 880 AssertPtr(pObj); 881 882 RTCString strPath = pObj->GetPath(); 883 if (strPath.isEmpty()) 884 return VERR_INVALID_PARAMETER; 885 if (strPath.length() >= RTPATH_MAX) /* Note: Maximum is RTPATH_MAX on guest side. */ 886 return VERR_BUFFER_OVERFLOW; 887 888 LogRel2(("DnD: Transferring host directory '%s' to guest\n", strPath.c_str())); 898 int GuestDnDTarget::i_sendDirectory(GuestDnDSendCtx *pCtx, PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg) 899 { 900 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 901 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 902 903 const char *pcszDstPath = DnDTransferObjectGetDestPath(pObj); 904 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER); 905 const size_t cchPath = RTStrNLen(pcszDstPath, RTPATH_MAX); /* Note: Maximum is RTPATH_MAX on guest side. */ 906 AssertReturn(cchPath, VERR_INVALID_PARAMETER); 907 908 LogRel2(("DnD: Transferring host directory '%s' to guest\n", DnDTransferObjectGetSourcePath(pObj))); 889 909 890 910 pMsg->setType(HOST_DND_HG_SND_DIR); 891 911 if (mDataBase.m_uProtocolVersion >= 3) 892 912 pMsg->setNextUInt32(0); /** @todo ContextID not used yet. */ 893 pMsg->setNextString( strPath.c_str());/* path */894 pMsg->setNextUInt32((uint32_t)( strPath.length() + 1)); /* path length (maximum is RTPATH_MAX on guest side). */895 pMsg->setNextUInt32( pObj->GetMode());/* mode */913 pMsg->setNextString(pcszDstPath); /* path */ 914 pMsg->setNextUInt32((uint32_t)(cchPath + 1)); /* path length, including terminator. */ 915 pMsg->setNextUInt32(DnDTransferObjectGetMode(pObj)); /* mode */ 896 916 897 917 return VINF_SUCCESS; 898 918 } 899 919 900 int GuestDnDTarget::i_sendFile(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg) 901 { 902 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 903 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER); 904 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 905 906 DnDURIObject *pObj = pObjCtx->getObj(); 907 AssertPtr(pObj); 908 909 RTCString strPathSrc = pObj->GetPath(); 910 if (strPathSrc.isEmpty()) 911 return VERR_INVALID_PARAMETER; 920 /** 921 * Sends a transfer file to the guest. 922 * 923 * @returns VBox status code. 924 * @param pCtx 925 * @param pObj 926 * @param pMsg 927 */ 928 int GuestDnDTarget::i_sendFile(GuestDnDSendCtx *pCtx, 929 PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg) 930 { 931 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 932 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 933 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 934 935 const char *pcszSrcPath = DnDTransferObjectGetSourcePath(pObj); 936 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER); 937 const char *pcszDstPath = DnDTransferObjectGetDestPath(pObj); 938 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER); 912 939 913 940 int rc = VINF_SUCCESS; 914 941 915 LogFlowFunc(("Sending file with %RU32 bytes buffer, using protocol v%RU32 ...\n", 916 mData.mcbBlockSize, mDataBase.m_uProtocolVersion)); 917 LogFlowFunc(("strPathSrc=%s, fIsOpen=%RTbool, cbSize=%RU64\n", strPathSrc.c_str(), pObj->IsOpen(), pObj->GetSize())); 918 919 if (!pObj->IsOpen()) 920 { 921 LogRel2(("DnD: Opening host file '%s' for transferring to guest\n", strPathSrc.c_str())); 922 rc = pObj->Init(DnDURIObject::Type_File, strPathSrc); 923 if (RT_SUCCESS(rc)) 924 rc = pObj->Open(RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); 925 942 if (!DnDTransferObjectIsOpen(pObj)) 943 { 944 LogRel2(("DnD: Opening host file '%s' for transferring to guest\n", pcszSrcPath)); 945 946 rc = DnDTransferObjectOpen(pObj, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, 0 /* fMode */, 947 DNDTRANSFEROBJECT_FLAGS_NONE); 926 948 if (RT_FAILURE(rc)) 927 LogRel(("DnD: Opening host file '%s' failed, rc=%Rrc\n", strPathSrc.c_str(), rc)); 928 } 949 LogRel(("DnD: Opening host file '%s' failed, rc=%Rrc\n", pcszSrcPath, rc)); 950 } 951 952 if (RT_FAILURE(rc)) 953 return rc; 929 954 930 955 bool fSendData = false; … … 933 958 if (mDataBase.m_uProtocolVersion >= 2) 934 959 { 935 uint32_t fState = pObjCtx->getState(); 936 if (!(fState & DND_OBJCTX_STATE_HAS_HDR)) 960 if (!(pCtx->mTransfer.mfObjState & DND_OBJ_STATE_HAS_HDR)) 937 961 { 962 const size_t cchDstPath = RTStrNLen(pcszDstPath, RTPATH_MAX); 963 const size_t cbSize = DnDTransferObjectGetSize(pObj); 964 const RTFMODE fMode = DnDTransferObjectGetMode(pObj); 965 938 966 /* 939 967 * Since protocol v2 the file header and the actual file contents are … … 943 971 pMsg->setType(HOST_DND_HG_SND_FILE_HDR); 944 972 pMsg->setNextUInt32(0); /** @todo ContextID not used yet. */ 945 pMsg->setNextString(pObj->GetPath().c_str()); /* pvName */ 946 pMsg->setNextUInt32((uint32_t)(pObj->GetPath().length() + 1)); /* cbName */ 947 pMsg->setNextUInt32(0); /* uFlags */ 948 pMsg->setNextUInt32(pObj->GetMode()); /* fMode */ 949 pMsg->setNextUInt64(pObj->GetSize()); /* uSize */ 950 951 LogFlowFunc(("Sending file header ...\n")); 952 LogRel2(("DnD: Transferring host file '%s' to guest (%RU64 bytes, mode 0x%x)\n", 953 pObj->GetPath().c_str(), pObj->GetSize(), pObj->GetMode())); 973 pMsg->setNextString(pcszDstPath); /* pvName */ 974 pMsg->setNextUInt32((uint32_t)(cchDstPath + 1)); /* cbName */ 975 pMsg->setNextUInt32(0); /* uFlags */ 976 pMsg->setNextUInt32(fMode); /* fMode */ 977 pMsg->setNextUInt64(cbSize); /* uSize */ 978 979 LogRel2(("DnD: Transferring host file '%s' to guest (%zu bytes, mode %#x)\n", 980 pcszSrcPath, cbSize, fMode)); 954 981 955 982 /** @todo Set progress object title to current file being transferred? */ 956 983 957 pObjCtx->setState(fState | DND_OBJCTX_STATE_HAS_HDR); 984 /* Update object state to reflect that we have sent the file header. */ 985 pCtx->mTransfer.mfObjState |= DND_OBJ_STATE_HAS_HDR; 958 986 } 959 987 else … … 973 1001 && fSendData) 974 1002 { 975 rc = i_sendFileData(pCtx, pObj Ctx, pMsg);1003 rc = i_sendFileData(pCtx, pObj, pMsg); 976 1004 } 977 1005 978 1006 if (RT_FAILURE(rc)) 979 LogRel(("DnD: Sending host file to guest failed, rc=%Rrc\n", rc));1007 LogRel(("DnD: Sending host file '%s' to guest failed, rc=%Rrc\n", pcszSrcPath, rc)); 980 1008 981 1009 LogFlowFuncLeaveRC(rc); … … 983 1011 } 984 1012 985 int GuestDnDTarget::i_sendFileData(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg) 986 { 987 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 988 AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER); 989 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 990 991 DnDURIObject *pObj = pObjCtx->getObj(); 992 AssertPtr(pObj); 993 994 AssertPtr(pCtx->mpResp); 1013 int GuestDnDTarget::i_sendFileData(GuestDnDSendCtx *pCtx, 1014 PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg) 1015 { 1016 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1017 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 1018 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 1019 1020 AssertPtrReturn(pCtx->mpResp, VERR_WRONG_ORDER); 995 1021 996 1022 /** @todo Don't allow concurrent reads per context! */ 997 998 /*999 * Start sending stuff.1000 */1001 1023 1002 1024 /* Set the message type. */ 1003 1025 pMsg->setType(HOST_DND_HG_SND_FILE_DATA); 1026 1027 const char *pcszSrcPath = DnDTransferObjectGetSourcePath(pObj); 1028 const char *pcszDstPath = DnDTransferObjectGetDestPath(pObj); 1004 1029 1005 1030 /* Protocol version 1 sends the file path *every* time with a new file chunk. … … 1007 1032 if (mDataBase.m_uProtocolVersion <= 1) 1008 1033 { 1009 pMsg->setNextString(pObj->GetPath().c_str()); /* pvName */ 1010 pMsg->setNextUInt32((uint32_t)(pObj->GetPath().length() + 1)); /* cbName */ 1034 const size_t cchDstPath = RTStrNLen(pcszDstPath, RTPATH_MAX); 1035 1036 pMsg->setNextString(pcszDstPath); /* pvName */ 1037 pMsg->setNextUInt32((uint32_t)cchDstPath + 1); /* cbName */ 1011 1038 } 1012 1039 else if (mDataBase.m_uProtocolVersion >= 2) 1013 1040 { 1014 pMsg->setNextUInt32(0); /** @todo ContextID not used yet. */ 1015 } 1016 1017 uint32_t cbRead = 0; 1018 1019 int rc = pObj->Read(pCtx->mURI.getBufferMutable(), pCtx->mURI.getBufferSize(), &cbRead); 1041 pMsg->setNextUInt32(0); /** @todo ContextID not used yet. */ 1042 } 1043 1044 void *pvBuf = pCtx->mTransfer.pvScratchBuf; 1045 AssertPtr(pvBuf); 1046 size_t cbBuf = pCtx->mTransfer.cbScratchBuf; 1047 Assert(cbBuf); 1048 1049 uint32_t cbRead; 1050 1051 int rc = DnDTransferObjectRead(pObj, pvBuf, cbBuf, &cbRead); 1020 1052 if (RT_SUCCESS(rc)) 1021 1053 { 1022 pCtx->mData.addProcessed(cbRead); 1023 LogFlowFunc(("cbBufSize=%zu, cbRead=%RU32\n", pCtx->mURI.getBufferSize(), cbRead)); 1054 pCtx->addProcessed(cbRead); 1055 1056 LogFlowFunc(("cbBufe=%zu, cbRead=%RU32\n", cbBuf, cbRead)); 1024 1057 1025 1058 if (mDataBase.m_uProtocolVersion <= 1) 1026 1059 { 1027 pMsg->setNextPointer(p Ctx->mURI.getBufferMutable(), cbRead);/* pvData */1060 pMsg->setNextPointer(pvBuf, cbRead); /* pvData */ 1028 1061 pMsg->setNextUInt32(cbRead); /* cbData */ 1029 pMsg->setNextUInt32( pObj->GetMode());/* fMode */1062 pMsg->setNextUInt32(DnDTransferObjectGetMode(pObj)); /* fMode */ 1030 1063 } 1031 1064 else /* Protocol v2 and up. */ 1032 1065 { 1033 pMsg->setNextPointer(p Ctx->mURI.getBufferMutable(), cbRead);/* pvData */1066 pMsg->setNextPointer(pvBuf, cbRead); /* pvData */ 1034 1067 pMsg->setNextUInt32(cbRead); /* cbData */ 1035 1068 … … 1042 1075 } 1043 1076 1044 if (pObj->IsComplete()) /* Done reading? */ 1045 { 1046 LogRel2(("DnD: Transferring file '%s' to guest complete\n", pObj->GetPath().c_str())); 1047 LogFlowFunc(("File '%s' complete\n", pObj->GetPath().c_str())); 1048 1049 /* DnDURIObject::Read() returns VINF_EOF when finished reading the entire fire, 1050 * but we don't want this here -- so just override this with VINF_SUCCESS. */ 1077 if (DnDTransferObjectIsComplete(pObj)) /* Done reading? */ 1078 { 1079 LogRel2(("DnD: Transferring host file '%s' to guest complete\n", pcszSrcPath)); 1080 1081 /* DnDTransferObjectRead() returns VINF_EOF when finished reading the entire file, 1082 * but we don't want this here -- so just set VINF_SUCCESS. */ 1051 1083 rc = VINF_SUCCESS; 1052 1084 } 1053 1085 } 1054 1055 if (RT_FAILURE(rc)) 1056 LogRel(("DnD: Reading from host file '%s' failed, rc=%Rrc\n", pObj->GetPath().c_str(), rc)); 1086 else 1087 LogRel(("DnD: Reading from host file '%s' failed, rc=%Rrc\n", pcszSrcPath, rc)); 1057 1088 1058 1089 LogFlowFuncLeaveRC(rc); … … 1096 1127 GuestDnDMsg *pMsg = new GuestDnDMsg(); 1097 1128 1098 rc = pThis->i_send URIDataLoop(pCtx, pMsg);1129 rc = pThis->i_sendTransferDataLoop(pCtx, pMsg); 1099 1130 if (rc == VINF_EOF) /* Transfer complete? */ 1100 1131 { … … 1272 1303 } 1273 1304 1274 int GuestDnDTarget::i_sendURIData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout) 1305 /** 1306 * Main function for sending the actual transfer data (i.e. files + directories) to the guest. 1307 * 1308 * @returns VBox status code. 1309 * @param pCtx Send context to use. 1310 * @param msTimeout Timeout (in ms) to use for getting the data sent. 1311 */ 1312 int GuestDnDTarget::i_sendTransferData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout) 1275 1313 { 1276 1314 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 1290 1328 } while (0) 1291 1329 1292 int rc = pCtx->m URI.init(mData.mcbBlockSize);1330 int rc = pCtx->mTransfer.init(mData.mcbBlockSize); 1293 1331 if (RT_FAILURE(rc)) 1294 1332 return rc; … … 1315 1353 { 1316 1354 /* 1317 * Extract URIlist from current meta data.1355 * Extract transfer list from current meta data. 1318 1356 */ 1319 GuestDnDData *pData = &pCtx->mData; 1320 GuestDnDURIData *pURI = &pCtx->mURI; 1321 1322 rc = pURI->fromLocalMetaData(pData->getMeta()); 1357 rc = DnDTransferListAppendPathsFromBuffer(&pCtx->mTransfer.mList, DNDTRANSFERLISTFMT_NATIVE, 1358 (const char *)pCtx->Meta.pvData, pCtx->Meta.cbData, "\n", DNDTRANSFERLIST_FLAGS_NONE); 1323 1359 if (RT_FAILURE(rc)) 1324 1360 break; 1325 1361 1326 LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n",1327 pURI->getURIList().GetRootCount(), pURI->getURIList().GetTotalBytes()));1328 1329 1362 /* 1330 * Set the new meta data with the URI list in it.1363 * Set the extra data size 1331 1364 */ 1332 rc = pData->getMeta().fromURIList(pURI->getURIList()); 1333 if (RT_FAILURE(rc)) 1334 break; 1335 1336 /* 1337 * Set the estimated data sizes we are going to send. 1338 * The total size also contains the meta data size. 1339 */ 1340 const uint32_t cbMeta = pData->getMeta().getSize(); 1341 pData->setEstimatedSize(pURI->getURIList().GetTotalBytes() + cbMeta /* cbTotal */, 1342 cbMeta /* cbMeta */); 1343 1344 /* 1345 * Set the meta format. 1346 */ 1347 void *pvFmt = (void *)pCtx->mFmtReq.c_str(); 1348 uint32_t cbFmt = (uint32_t)pCtx->mFmtReq.length() + 1; /* Include terminating zero. */ 1349 1350 pData->setFmt(pvFmt, cbFmt); 1365 pCtx->cbExtra = DnDTransferListObjTotalBytes(&pCtx->mTransfer.mList); 1351 1366 1352 1367 /* 1353 1368 * The first message always is the data header. The meta data itself then follows 1354 * and *only* contains the root elements of a n URIlist.1369 * and *only* contains the root elements of a transfer list. 1355 1370 * 1356 1371 * After the meta data we generate the messages required to send the … … 1365 1380 */ 1366 1381 if (mDataBase.m_uProtocolVersion >= 3) 1367 rc = i_send DataHeader(pCtx, pData, &pCtx->mURI);1382 rc = i_sendMetaDataHeader(pCtx); 1368 1383 1369 1384 /* … … 1371 1386 */ 1372 1387 if (RT_SUCCESS(rc)) 1373 rc = i_send DataBody(pCtx, pData);1388 rc = i_sendMetaDataBody(pCtx); 1374 1389 1375 1390 if (RT_SUCCESS(rc)) … … 1411 1426 AssertRC(rc2); 1412 1427 1428 LogRel2(("DnD: Sending transfer data to guest cancelled by user\n")); 1429 1413 1430 rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS); 1414 1431 AssertRC(rc2); … … 1416 1433 else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */ 1417 1434 { 1435 LogRel(("DnD: Sending transfer data to guest failed with rc=%Rrc\n", rc)); 1418 1436 int rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc, 1419 1437 GuestDnDTarget::i_hostErrorToString(rc)); … … 1428 1446 } 1429 1447 1430 int GuestDnDTarget::i_send URIDataLoop(GuestDnDSendCtx *pCtx, GuestDnDMsg *pMsg)1448 int GuestDnDTarget::i_sendTransferDataLoop(GuestDnDSendCtx *pCtx, GuestDnDMsg *pMsg) 1431 1449 { 1432 1450 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1433 1451 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 1434 1452 1435 int rc = updateProgress( &pCtx->mData, pCtx->mpResp);1453 int rc = updateProgress(pCtx, pCtx->mpResp); 1436 1454 AssertRC(rc); 1437 1455 1438 if ( pCtx-> mData.isComplete()1439 && pCtx->m URI.isComplete())1456 if ( pCtx->isComplete() 1457 && pCtx->mTransfer.isComplete()) 1440 1458 { 1441 1459 return VINF_EOF; 1442 1460 } 1443 1461 1444 GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObjCurrent();1445 if (! objCtx.isValid())1462 PDNDTRANSFEROBJECT pObj = DnDTransferListObjGetFirst(&pCtx->mTransfer.mList); 1463 if (!pObj) 1446 1464 return VERR_WRONG_ORDER; 1447 1465 1448 DnDURIObject *pCurObj = objCtx.getObj(); 1449 AssertPtr(pCurObj); 1450 1451 const DnDURIObject::Type enmType = pCurObj->GetType(); 1452 1453 LogRel3(("DnD: Processing: srcPath=%s, dstPath=%s, enmType=%RU32, cbSize=%RU32\n", 1454 pCurObj->GetPath().c_str(), pCurObj->GetPath().c_str(), 1455 enmType, pCurObj->GetSize())); 1456 1457 if (enmType == DnDURIObject::Type_Directory) 1458 { 1459 rc = i_sendDirectory(pCtx, &objCtx, pMsg); 1460 } 1461 else if (DnDURIObject::Type_File) 1462 { 1463 rc = i_sendFile(pCtx, &objCtx, pMsg); 1464 } 1465 else 1466 { 1467 AssertMsgFailed(("enmType=%RU32 is not supported for srcPath=%s, dstPath=%s\n", 1468 enmType, pCurObj->GetPath().c_str(), pCurObj->GetPath().c_str())); 1469 rc = VERR_NOT_SUPPORTED; 1470 } 1471 1472 bool fRemove = false; /* Remove current entry? */ 1473 if ( pCurObj->IsComplete() 1466 switch (DnDTransferObjectGetType(pObj)) 1467 { 1468 case DNDTRANSFEROBJTYPE_DIRECTORY: 1469 rc = i_sendDirectory(pCtx, pObj, pMsg); 1470 break; 1471 1472 case DNDTRANSFEROBJTYPE_FILE: 1473 rc = i_sendFile(pCtx, pObj, pMsg); 1474 break; 1475 1476 default: 1477 AssertFailedStmt(rc = VERR_NOT_SUPPORTED); 1478 break; 1479 } 1480 1481 if ( DnDTransferObjectIsComplete(pObj) 1474 1482 || RT_FAILURE(rc)) 1475 { 1476 fRemove = true; 1477 } 1478 1479 if (fRemove) 1480 { 1481 LogFlowFunc(("Removing \"%s\" from list, rc=%Rrc\n", pCurObj->GetPath().c_str(), rc)); 1482 pCtx->mURI.removeObjCurrent(); 1483 } 1483 DnDTransferListObjRemoveFirst(&pCtx->mTransfer.mList); 1484 1484 1485 1485 LogFlowFuncLeaveRC(rc); … … 1487 1487 } 1488 1488 1489 /** 1490 * Main function for sending raw data (e.g. text, RTF, ...) to the guest. 1491 * 1492 * @returns VBox status code. 1493 * @param pCtx Send context to use. 1494 * @param msTimeout Timeout (in ms) to use for getting the data sent. 1495 */ 1489 1496 int GuestDnDTarget::i_sendRawData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout) 1490 1497 { 1491 1498 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1492 1499 NOREF(msTimeout); 1493 1494 GuestDnDData *pData = &pCtx->mData;1495 1500 1496 1501 /** @todo At the moment we only allow sending up to 64K raw data. 1497 1502 * For protocol v1+v2: Fix this by using HOST_DND_HG_SND_MORE_DATA. 1498 1503 * For protocol v3 : Send another HOST_DND_HG_SND_DATA message. */ 1499 if (!p Data->getMeta().getSize())1504 if (!pCtx->Meta.cbData) 1500 1505 return VINF_SUCCESS; 1501 1506 1502 int rc = VINF_SUCCESS; 1503 1504 /* 1505 * Send the data header first. 1506 */ 1507 if (mDataBase.m_uProtocolVersion >= 3) 1508 rc = i_sendDataHeader(pCtx, pData, NULL /* URI list */); 1509 1510 /* 1511 * Send the (meta) data body. 1512 */ 1507 int rc = i_sendMetaDataHeader(pCtx); 1513 1508 if (RT_SUCCESS(rc)) 1514 rc = i_send DataBody(pCtx, pData);1509 rc = i_sendMetaDataBody(pCtx); 1515 1510 1516 1511 int rc2; 1517 1512 if (RT_FAILURE(rc)) 1518 rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc, 1513 { 1514 LogRel(("DnD: Sending raw data to guest failed with rc=%Rrc\n", rc)); 1515 rc2 = pCtx->mpResp->setProgress(100 /* Percent */, DND_PROGRESS_ERROR, rc, 1519 1516 GuestDnDTarget::i_hostErrorToString(rc)); 1517 } 1520 1518 else 1521 rc2 = pCtx->mpResp->setProgress(100 , DND_PROGRESS_COMPLETE, rc);1519 rc2 = pCtx->mpResp->setProgress(100 /* Percent */, DND_PROGRESS_COMPLETE, rc); 1522 1520 AssertRC(rc2); 1523 1521 … … 1526 1524 } 1527 1525 1526 /** 1527 * Cancels sending DnD data. 1528 * 1529 * @returns VBox status code. 1530 * @param aVeto Whether cancelling was vetoed or not. 1531 * Not implemented yet. 1532 */ 1528 1533 HRESULT GuestDnDTarget::cancel(BOOL *aVeto) 1529 1534 { … … 1532 1537 #else /* VBOX_WITH_DRAG_AND_DROP */ 1533 1538 1539 LogRel2(("DnD: Sending cancelling request to the guest ...\n")); 1540 1534 1541 int rc = GuestDnDBase::sendCancel(); 1535 1542 1536 1543 if (aVeto) 1537 *aVeto = FALSE; /** @todo */1544 *aVeto = FALSE; /** @todo Impplement vetoing. */ 1538 1545 1539 1546 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
Note:
See TracChangeset
for help on using the changeset viewer.