Changeset 85371 in vbox for trunk/src/VBox
- Timestamp:
- Jul 17, 2020 10:02:58 AM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 139382
- Location:
- trunk/src/VBox
- Files:
-
- 17 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
r85121 r85371 1068 1068 int VBoxDnDWnd::OnHgDataReceive(PVBGLR3GUESTDNDMETADATA pMeta) 1069 1069 { 1070 LogFlowThisFunc(("mState=%ld, enmMetaType=%RU32, cbMeta=%RU32\n", mState, pMeta->enmType, pMeta->cbMeta)); 1071 1072 mState = Dropped; 1073 1074 int rc = VINF_SUCCESS; 1075 if (pMeta->pvMeta) 1076 { 1077 Assert(pMeta->cbMeta); 1078 rc = RTCritSectEnter(&mCritSect); 1070 LogFlowThisFunc(("mState=%ld, enmMetaType=%RU32\n", mState, pMeta->enmType)); 1071 1072 int rc = RTCritSectEnter(&mCritSect); 1073 if (RT_SUCCESS(rc)) 1074 { 1075 mState = Dropped; 1076 1077 if (startupInfo.pDataObject) 1078 { 1079 switch (pMeta->enmType) 1080 { 1081 case VBGLR3GUESTDNDMETADATATYPE_RAW: 1082 { 1083 AssertBreakStmt(pMeta->u.Raw.pvMeta != NULL, rc = VERR_INVALID_POINTER); 1084 AssertBreakStmt(pMeta->u.Raw.cbMeta, rc = VERR_INVALID_PARAMETER); 1085 1086 rc = startupInfo.pDataObject->Signal(mFormatRequested, pMeta->u.Raw.pvMeta, pMeta->u.Raw.cbMeta); 1087 break; 1088 } 1089 1090 case VBGLR3GUESTDNDMETADATATYPE_URI_LIST: 1091 { 1092 LogRel2(("DnD: URI transfer root directory is '%s'\n", DnDTransferListGetRootPathAbs(&pMeta->u.URI.Transfer))); 1093 1094 char *pszBuf; 1095 size_t cbBuf; 1096 /* Note: The transfer list already has its root set to a temporary directory, so no need to set/add a new 1097 * path base here. */ 1098 rc = DnDTransferListGetRootsEx(&pMeta->u.URI.Transfer, DNDTRANSFERLISTFMT_NATIVE, NULL /* pszPathBase */, 1099 DND_PATH_SEPARATOR, &pszBuf, &cbBuf); 1100 if (RT_SUCCESS(rc)) 1101 { 1102 rc = startupInfo.pDataObject->Signal(mFormatRequested, pszBuf, cbBuf); 1103 RTStrFree(pszBuf); 1104 } 1105 break; 1106 } 1107 1108 default: 1109 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 1110 break; 1111 } 1112 } 1113 else 1114 rc = VERR_NOT_FOUND; 1115 1116 int rc2 = mouseRelease(); 1079 1117 if (RT_SUCCESS(rc)) 1080 { 1081 if (startupInfo.pDataObject) 1082 rc = startupInfo.pDataObject->Signal(mFormatRequested, pMeta->pvMeta, pMeta->cbMeta); 1083 else 1084 rc = VERR_NOT_FOUND; 1085 1086 RTCritSectLeave(&mCritSect); 1087 } 1088 } 1089 1090 int rc2 = mouseRelease(); 1091 if (RT_SUCCESS(rc)) 1092 rc = rc2; 1118 rc = rc2; 1119 1120 RTCritSectLeave(&mCritSect); 1121 } 1093 1122 1094 1123 LogFlowFuncLeaveRC(rc); -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h
r85121 r85371 71 71 int Abort(void); 72 72 void SetStatus(Status status); 73 int Signal(const RTCString &strFormat, const void *pvData, uint32_t cbData);73 int Signal(const RTCString &strFormat, const void *pvData, size_t cbData); 74 74 75 75 protected: … … 88 88 RTCString mstrFormat; 89 89 void *mpvData; 90 uint32_tmcbData;90 size_t mcbData; 91 91 }; 92 92 -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDataObject.cpp
r82968 r85371 229 229 * URI list handling. 230 230 */ 231 if ( mstrFormat.equalsIgnoreCase("text/uri-list"))231 if (DnDMIMEHasFileURLs(mstrFormat.c_str(), RTSTR_MAX)) 232 232 { 233 int rc = VINF_SUCCESS; 234 235 RTCList<RTCString> lstFilesURI = RTCString((char*)mpvData, mcbData).split("\r\n"); 236 RTCList<RTCString> lstFiles; 237 for (size_t i = 0; i < lstFilesURI.size(); i++) 238 { 239 char *pszFilePath = RTUriFilePath(lstFilesURI.at(i).c_str()); 240 if (pszFilePath) 241 { 242 lstFiles.append(pszFilePath); 243 RTStrFree(pszFilePath); 244 } 245 else /* Unable to parse -- refuse entire request. */ 246 { 247 lstFiles.clear(); 248 rc = VERR_INVALID_PARAMETER; 249 break; 250 } 251 } 252 253 size_t cFiles = lstFiles.size(); 233 char **papszFiles; 234 size_t cFiles; 235 int rc = RTStrSplit((const char *)mpvData, mcbData, DND_PATH_SEPARATOR, &papszFiles, &cFiles); 254 236 if ( RT_SUCCESS(rc) 255 237 && cFiles) 256 238 { 257 #ifdef DEBUG 258 LogFlowFunc(("Files (%zu)\n", cFiles)); 239 LogRel2(("DnD: Files (%zu)\n", cFiles)); 259 240 for (size_t i = 0; i < cFiles; i++) 260 LogFlowFunc(("\tFile: %s\n", lstFiles.at(i).c_str())); 261 #endif 241 LogRel2(("\tDnD: File '%s'\n", papszFiles[i])); 262 242 263 243 #if 0 … … 310 290 for (size_t i = 0; i < cFiles; i++) 311 291 { 312 cchFiles += strlen( lstFiles.at(i).c_str());292 cchFiles += strlen(papszFiles[i]); 313 293 cchFiles += 1; /* Terminating '\0'. */ 314 294 } … … 328 308 size_t cchCurFile; 329 309 PRTUTF16 pwszFile; 330 rc = RTStrToUtf16( lstFiles.at(i).c_str(), &pwszFile);310 rc = RTStrToUtf16(papszFiles[i], &pwszFile); 331 311 if (RT_SUCCESS(rc)) 332 312 { … … 373 353 rc = VERR_NO_MEMORY; 374 354 } 355 356 for (size_t i = 0; i < cFiles; ++i) 357 RTStrFree(papszFiles[i]); 358 RTMemFree(papszFiles); 375 359 } 376 360 … … 671 655 672 656 int VBoxDnDDataObject::Signal(const RTCString &strFormat, 673 const void *pvData, uint32_t cbData)657 const void *pvData, size_t cbData) 674 658 { 675 659 int rc; -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp
r82968 r85371 28 28 #include "VBox/HostServices/DragAndDropSvc.h" 29 29 30 #include <iprt/path.h> 30 31 #include <iprt/utf16.h> 31 32 #include <VBox/log.h> … … 451 452 LogRel(("DnD: Adding guest file '%s'\n", pszFileUtf8)); 452 453 453 rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, pszFileUtf8, cchFileUtf8);454 454 if (RT_SUCCESS(rc)) 455 cchFiles += cchFileUtf8; 455 { 456 rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */, pszFileUtf8, cchFileUtf8); 457 if (RT_SUCCESS(rc)) 458 cchFiles += cchFileUtf8; 459 } 456 460 } 457 else 461 462 if (RT_FAILURE(rc)) 458 463 LogRel(("DnD: Error handling file entry #%u, rc=%Rrc\n", i, rc)); 459 464 460 if (pszFileUtf8) 461 RTStrFree(pszFileUtf8); 465 RTStrFree(pszFileUtf8); 462 466 463 467 if (RT_FAILURE(rc)) … … 479 483 cFiles, cchFiles, cbFiles, pszFiles)); 480 484 481 /* Translate the list into URI elements. */ 482 DnDURIList lstURI; 483 rc = lstURI.AppendNativePathsFromList(pszFiles, cbFiles, 484 DNDURILIST_FLAGS_ABSOLUTE_PATHS); 485 if (RT_SUCCESS(rc)) 486 { 487 RTCString strRoot = lstURI.GetRootEntries(); 488 size_t cbRoot = strRoot.length() + 1; /* Include termination */ 489 490 mpvData = RTMemAlloc(cbRoot); 491 if (mpvData) 492 { 493 memcpy(mpvData, strRoot.c_str(), cbRoot); 494 mcbData = cbRoot; 495 } 496 else 497 rc = VERR_NO_MEMORY; 498 } 485 mpvData = pszFiles; 486 mcbData = cbFiles; 499 487 } 500 501 LogFlowFunc(("Building CF_HDROP list rc=%Rrc, pszFiles=0x%p, cFiles=%RU16, cchFiles=%RU32\n", 502 rc, pszFiles, cFiles, cchFiles)); 503 504 if (pszFiles) 488 else 489 { 505 490 RTStrFree(pszFiles); 491 pszFiles = NULL; 492 } 493 494 LogFlowFunc(("Building CF_HDROP list rc=%Rrc, cFiles=%RU16, cchFiles=%RU32\n", 495 rc, cFiles, cchFiles)); 506 496 break; 507 497 } -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
r85121 r85371 154 154 static VBOXSERVICEINFO g_aServices[] = 155 155 { 156 { &g_SvcDescClipboard, NIL_RTTHREAD, NULL, false, false, false, false, true }156 {&g_SvcDescDnD, NIL_RTTHREAD, NULL, false, false, false, false, true } 157 157 }; 158 158 #else -
trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibDragAndDrop.cpp
r85029 r85371 349 349 * @param pDroppedFiles Dropped files object to use for maintaining the file creation / locking. 350 350 */ 351 static int vbglR3DnDHGRecvURIData(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr, DnDDroppedFiles *pDroppedFiles)351 static int vbglR3DnDHGRecvURIData(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr, PDNDDROPPEDFILES pDroppedFiles) 352 352 { 353 353 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 384 384 * Create and query the (unique) drop target directory in the user's temporary directory. 385 385 */ 386 int rc = pDroppedFiles->OpenTemp(0 /* fFlags */);386 int rc = DnDDroppedFilesOpenTemp(pDroppedFiles, 0 /* fFlags */); 387 387 if (RT_FAILURE(rc)) 388 388 { … … 391 391 } 392 392 393 const char *pszDropDir = pDroppedFiles->GetDirAbs();393 const char *pszDropDir = DnDDroppedFilesGetDirAbs(pDroppedFiles); 394 394 AssertPtr(pszDropDir); 395 395 … … 397 397 * Enter the main loop of retieving files + directories. 398 398 */ 399 DnDURIObject objFile; 399 DNDTRANSFEROBJECT objCur; 400 RT_ZERO(objCur); 400 401 401 402 char szPathName[RTPATH_MAX] = { 0 }; … … 424 425 &cbPathName, 425 426 &fMode); 426 LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n", 427 LogFlowFunc(("HOST_DND_HG_SND_DIR: " 428 "pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n", 427 429 szPathName, cbPathName, fMode, rc)); 428 430 … … 437 439 rc = RTDirCreate(pszPathAbs, fCreationMode, 0); 438 440 if (RT_SUCCESS(rc)) 439 rc = pDroppedFiles->AddDir(pszPathAbs);441 rc = DnDDroppedFilesAddDir(pDroppedFiles, pszPathAbs); 440 442 441 443 if (RT_SUCCESS(rc)) … … 452 454 } 453 455 case HOST_DND_HG_SND_FILE_HDR: 456 RT_FALL_THROUGH(); 454 457 case HOST_DND_HG_SND_FILE_DATA: 455 458 { … … 489 492 490 493 /* Is there already a file open, e.g. in transfer? */ 491 if (! objFile.IsOpen())494 if (!DnDTransferObjectIsOpen(&objCur)) 492 495 { 493 RTCString strPathAbs(pszPathAbs);494 496 #ifdef RT_OS_WINDOWS 495 497 uint32_t fCreationMode = (fMode & RTFS_DOS_MASK) | RTFS_DOS_NT_NORMAL; … … 497 499 uint32_t fCreationMode = (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR; 498 500 #endif 499 rc = objFile.Init(DnDURIObject::Type_File, strPathAbs); 501 rc = DnDTransferObjectInit(&objCur, DNDTRANSFEROBJTYPE_FILE, 502 pszDropDir /* Source (base) path */, szPathName /* Destination path */); 500 503 if (RT_SUCCESS(rc)) 501 504 { 502 rc = objFile.Open(fOpen, fCreationMode);505 rc = DnDTransferObjectOpen(&objCur, fOpen, fCreationMode, DNDTRANSFEROBJECT_FLAGS_NONE); 503 506 if (RT_SUCCESS(rc)) 504 507 { 505 rc = pDroppedFiles->AddFile(strPathAbs.c_str());508 rc = DnDDroppedFilesAddFile(pDroppedFiles, pszPathAbs); 506 509 if (RT_SUCCESS(rc)) 507 510 { 508 511 cbFileWritten = 0; 509 objFile.SetSize(cbFileSize);512 DnDTransferObjectSetSize(&objCur, cbFileSize); 510 513 } 511 514 } … … 514 517 else 515 518 { 516 AssertMsgFailed(("ObjType=%RU32\n", objFile.GetType()));519 AssertMsgFailed(("ObjType=%RU32\n", DnDTransferObjectGetType(&objCur))); 517 520 rc = VERR_WRONG_ORDER; 518 521 } … … 529 532 { 530 533 uint32_t cbChunkWritten; 531 rc = objFile.Write(pvChunk, cbChunkRead, &cbChunkWritten);534 rc = DnDTransferObjectWrite(&objCur, pvChunk, cbChunkRead, &cbChunkWritten); 532 535 if (RT_SUCCESS(rc)) 533 536 { 534 LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "537 LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA: " 535 538 "cbChunkRead=%RU32, cbChunkWritten=%RU32, cbFileWritten=%RU64 cbFileSize=%RU64\n", 536 539 cbChunkRead, cbChunkWritten, cbFileWritten + cbChunkWritten, cbFileSize)); … … 544 547 545 548 /* Data transfer complete? Close the file. */ 546 bool fClose = objFile.IsComplete();549 bool fClose = DnDTransferObjectIsComplete(&objCur); 547 550 if (fClose) 548 551 { … … 557 560 { 558 561 LogFlowFunc(("Closing file\n")); 559 objFile.Close();562 DnDTransferObjectDestroy(&objCur); 560 563 } 561 564 … … 604 607 if (RT_FAILURE(rc)) 605 608 { 606 objFile.Close();607 pDroppedFiles->Rollback();609 DnDTransferObjectDestroy(&objCur); 610 DnDDroppedFilesRollback(pDroppedFiles); 608 611 } 609 612 else 610 613 { 611 /** @todo Compare the URIlist with the dirs/files we really transferred. */614 /** @todo Compare the transfer list with the dirs/files we really transferred. */ 612 615 /** @todo Implement checksum verification, if any. */ 613 616 } … … 618 621 * by the client's drag'n drop operation lateron. 619 622 */ 620 int rc2 = pDroppedFiles->Reset(false /* fRemoveDropDir */);623 int rc2 = DnDDroppedFilesReset(pDroppedFiles, false /* fRemoveDropDir */); 621 624 if (RT_FAILURE(rc2)) /* Not fatal, don't report back to host. */ 622 625 LogFlowFunc(("Closing dropped files directory failed with %Rrc\n", rc2)); … … 805 808 /** 806 809 * Host -> Guest 807 * Main function for receiving the actual DnD data from the host, extended version. 808 * 809 * @returns IPRT status code. 810 * @param pCtx DnD context to use. 811 * @param pEnmType Where to store the meta data type. Optional. 812 * @param ppvData Returns the received meta data. Needs to be free'd by the caller. Optional. 813 * @param pcbData Where to store the size (in bytes) of the received meta data. Optional. 814 */ 815 static int vbglR3DnDHGRecvDataMainEx(PVBGLR3GUESTDNDCMDCTX pCtx, 816 VBGLR3GUESTDNDMETADATATYPE *pEnmType, 817 void **ppvData, 818 uint32_t *pcbData) 810 * Main function for receiving the actual DnD data from the host. 811 * 812 * @returns IPRT status code. 813 * @param pCtx DnD context to use. 814 * @param pMeta Where to store the actual meta data received from the host. 815 */ 816 static int vbglR3DnDHGRecvDataMain(PVBGLR3GUESTDNDCMDCTX pCtx, 817 PVBGLR3GUESTDNDMETADATA pMeta) 819 818 { 820 819 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 821 /* The rest is optional. */820 AssertPtrReturn(pMeta, VERR_INVALID_POINTER); 822 821 823 822 VBOXDNDDATAHDR dataHdr; … … 831 830 return VERR_NO_MEMORY; 832 831 833 DnDURIList lstURI; 834 DnDDroppedFiles droppedFiles; 832 DNDDROPPEDFILES droppedFiles; 835 833 836 834 void *pvData = NULL; … … 855 853 Assert(cbData); 856 854 857 rc = lstURI.SetFromURIData(pvData, cbData, 0 /* fFlags */); 855 /* Use the dropped files directory as the root directory for the current transfer. */ 856 rc = DnDTransferListInit(&pMeta->u.URI.Transfer, DnDDroppedFilesGetDirAbs(&droppedFiles)); 858 857 if (RT_SUCCESS(rc)) 859 rc = vbglR3DnDHGRecvURIData(pCtx, &dataHdr, &droppedFiles);860 861 if (RT_SUCCESS(rc)) /** @todo Remove this block as soon as we hand in DnDURIList. */862 858 { 863 if (pvData) 864 { 865 /* Reuse data buffer to fill in the transformed URI file list. */ 866 RTMemFree(pvData); 867 pvData = NULL; 868 } 869 870 RTCString strData = lstURI.GetRootEntries(droppedFiles.GetDirAbs()); 871 Assert(!strData.isEmpty()); 872 873 cbData = strData.length() + 1; 874 LogFlowFunc(("URI list has %zu bytes\n", cbData)); 875 876 pvData = RTMemAlloc(cbData); 877 if (pvData) 878 { 879 memcpy(pvData, strData.c_str(), cbData); 880 881 if (pEnmType) 882 *pEnmType = VBGLR3GUESTDNDMETADATATYPE_URI_LIST; 883 } 884 else 885 rc = VERR_NO_MEMORY; 859 rc = DnDTransferListAppendPathsFromBuffer(&pMeta->u.URI.Transfer, DNDTRANSFERLISTFMT_URI, (const char *)pvData, cbData, 860 DND_PATH_SEPARATOR, 0 /* fFlags */); 861 if (RT_SUCCESS(rc)) 862 rc = vbglR3DnDHGRecvURIData(pCtx, &dataHdr, &droppedFiles); 886 863 } 887 864 } 888 865 else /* Raw data. */ 889 866 { 890 if (pEnmType) 891 *pEnmType = VBGLR3GUESTDNDMETADATATYPE_RAW; 867 pMeta->enmType = VBGLR3GUESTDNDMETADATATYPE_RAW; 892 868 } 893 869 } … … 898 874 if (RT_SUCCESS(rc)) 899 875 { 900 if ( pvData 901 && cbData) 902 { 903 if (pcbData) 904 *pcbData = cbData; 905 if (ppvData) 906 *ppvData = pvData; 907 else 908 RTMemFree(pvData); 909 } 876 910 877 } 911 878 else if ( RT_FAILURE(rc) … … 921 888 922 889 LogFlowFuncLeaveRC(rc); 923 return rc;924 }925 926 /**927 * Host -> Guest928 * Main function for receiving the actual DnD data from the host.929 *930 * @returns IPRT status code.931 * @param pCtx DnD context to use.932 * @param pMeta Where to store the actual meta data received from the host.933 */934 static int vbglR3DnDHGRecvDataMain(PVBGLR3GUESTDNDCMDCTX pCtx,935 PVBGLR3GUESTDNDMETADATA pMeta)936 {937 AssertPtrReturn(pMeta, VERR_INVALID_POINTER);938 939 int rc = vbglR3DnDHGRecvDataMainEx(pCtx,940 &pMeta->enmType,941 &pMeta->pvMeta,942 &pMeta->cbMeta);943 890 return rc; 944 891 } … … 1300 1247 { 1301 1248 PVBGLR3GUESTDNDMETADATA pMeta = &pEvent->u.HG_Received.Meta; 1302 if (pMeta->pvMeta)1249 switch (pMeta->enmType) 1303 1250 { 1304 Assert(pMeta->cbMeta); 1305 RTMemFree(pMeta->pvMeta); 1306 pMeta->cbMeta = 0; 1251 case VBGLR3GUESTDNDMETADATATYPE_RAW: 1252 { 1253 if (pMeta->u.Raw.pvMeta) 1254 { 1255 Assert(pMeta->u.Raw.cbMeta); 1256 RTMemFree(pMeta->u.Raw.pvMeta); 1257 pMeta->u.Raw.cbMeta = 0; 1258 } 1259 break; 1260 } 1261 1262 case VBGLR3GUESTDNDMETADATATYPE_URI_LIST: 1263 { 1264 DnDTransferListDestroy(&pMeta->u.URI.Transfer); 1265 break; 1266 } 1267 1268 default: 1269 break; 1307 1270 } 1308 1271 break; … … 1503 1466 * @returns IPRT status code. 1504 1467 * @param pCtx DnD context to use. 1505 * @param pObj URIobject containing the directory to send.1506 */ 1507 static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, D nDURIObject*pObj)1468 * @param pObj transfer object containing the directory to send. 1469 */ 1470 static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DNDTRANSFEROBJECT *pObj) 1508 1471 { 1509 1472 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 1510 1473 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1511 AssertReturn(pObj->GetType() == DnDURIObject::Type_Directory, VERR_INVALID_PARAMETER); 1512 1513 RTCString strPath = pObj->GetPath(); 1514 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n", 1515 strPath.c_str(), strPath.length(), pObj->GetMode())); 1516 1517 if (strPath.length() > RTPATH_MAX) 1474 AssertReturn(DnDTransferObjectGetType(pObj) == DNDTRANSFEROBJTYPE_DIRECTORY, VERR_INVALID_PARAMETER); 1475 1476 const char *pcszPath = DnDTransferObjectGetDestPath(pObj); 1477 const size_t cchPath = RTStrNLen(pcszPath, RTPATH_MAX); 1478 const RTFMODE fMode = DnDTransferObjectGetMode(pObj); 1479 1480 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n", pcszPath, cchPath, fMode)); 1481 1482 if (cchPath > RTPATH_MAX) /* Can't happen, but check anyway. */ 1518 1483 return VERR_INVALID_PARAMETER; 1519 1520 const uint32_t cbPath = (uint32_t)strPath.length() + 1; /* Include termination. */1521 1484 1522 1485 HGCMMsgGHSendDir Msg; … … 1524 1487 /** @todo Context ID not used yet. */ 1525 1488 Msg.u.v3.uContext.SetUInt32(0); 1526 Msg.u.v3.pvName.SetPtr((void *) strPath.c_str(), (uint32_t)cbPath);1527 Msg.u.v3.cbName.SetUInt32((uint32_t)c bPath);1528 Msg.u.v3.fMode.SetUInt32( pObj->GetMode());1489 Msg.u.v3.pvName.SetPtr((void *)pcszPath, (uint32_t)cchPath); 1490 Msg.u.v3.cbName.SetUInt32((uint32_t)cchPath + 1); /* Include termination. */ 1491 Msg.u.v3.fMode.SetUInt32(fMode); 1529 1492 1530 1493 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); … … 1537 1500 * @returns IPRT status code. 1538 1501 * @param pCtx DnD context to use. 1539 * @param pObj URIobject containing the file to send.1540 */ 1541 static int vbglR3DnDGHSendFile(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)1502 * @param pObj Transfer object containing the file to send. 1503 */ 1504 static int vbglR3DnDGHSendFile(PVBGLR3GUESTDNDCMDCTX pCtx, PDNDTRANSFEROBJECT pObj) 1542 1505 { 1543 1506 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1544 1507 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 1545 AssertReturn( pObj->GetType() == DnDURIObject::Type_File, VERR_INVALID_PARAMETER);1546 AssertReturn( pObj->IsOpen(),VERR_INVALID_STATE);1508 AssertReturn(DnDTransferObjectGetType(pObj) == DNDTRANSFEROBJTYPE_FILE, VERR_INVALID_PARAMETER); 1509 AssertReturn(DnDTransferObjectIsOpen(pObj), VERR_INVALID_STATE); 1547 1510 1548 1511 uint32_t cbBuf = _64K; /** @todo Make this configurable? */ … … 1551 1514 return VERR_NO_MEMORY; 1552 1515 1553 RTCString strPath = pObj->GetPath(); 1554 1555 LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(), 1556 pObj->GetSize(), pObj->GetMode())); 1516 const char *pcszPath = DnDTransferObjectGetDestPath(pObj); 1517 const size_t cchPath = RTStrNLen(pcszPath, RTPATH_MAX); 1518 const uint64_t cbSize = DnDTransferObjectGetSize(pObj); 1519 const RTFMODE fMode = DnDTransferObjectGetMode(pObj); 1520 1521 LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", pcszPath, cchPath, cbSize, fMode)); 1557 1522 1558 1523 HGCMMsgGHSendFileHdr MsgHdr; 1559 1524 VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, pCtx->uClientID, GUEST_DND_GH_SND_FILE_HDR, 6); 1560 1525 MsgHdr.uContext.SetUInt32(0); /* Context ID; unused at the moment. */ 1561 MsgHdr.pvName.SetPtr((void *) strPath.c_str(), (uint32_t)(strPath.length() + 1));1562 MsgHdr.cbName.SetUInt32((uint32_t)( strPath.length() + 1));1526 MsgHdr.pvName.SetPtr((void *)pcszPath, (uint32_t)(cchPath + 1)); /* Include termination. */ 1527 MsgHdr.cbName.SetUInt32((uint32_t)(cchPath + 1)); /* Ditto. */ 1563 1528 MsgHdr.uFlags.SetUInt32(0); /* Flags; unused at the moment. */ 1564 MsgHdr.fMode.SetUInt32( pObj->GetMode());/* File mode */1565 MsgHdr.cbTotal.SetUInt64( pObj->GetSize());/* File size (in bytes). */1529 MsgHdr.fMode.SetUInt32(fMode); /* File mode */ 1530 MsgHdr.cbTotal.SetUInt64(cbSize); /* File size (in bytes). */ 1566 1531 1567 1532 int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr)); … … 1580 1545 Msg.u.v3.cbChecksum.SetUInt32(0); 1581 1546 1582 uint64_t cbToReadTotal = pObj->GetSize();1547 uint64_t cbToReadTotal = cbSize; 1583 1548 uint64_t cbWrittenTotal = 0; 1584 1549 while (cbToReadTotal) … … 1587 1552 uint32_t cbRead = 0; 1588 1553 if (cbToRead) 1589 rc = pObj->Read(pvBuf, cbToRead, &cbRead);1554 rc = DnDTransferObjectRead(pObj, pvBuf, cbToRead, &cbRead); 1590 1555 1591 1556 LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n", … … 1612 1577 cbWrittenTotal += cbRead; 1613 1578 1614 LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, pObj->GetSize(), cbWrittenTotal * 100 / pObj->GetSize()));1579 LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, cbSize, cbWrittenTotal * 100 / cbSize)); 1615 1580 }; 1616 1581 } … … 1624 1589 /** 1625 1590 * Guest -> Host 1626 * Utility function to send a n URIobject from guest to the host.1627 * 1628 * @returns IPRT status code. 1629 * @param pCtx DnD context to use. 1630 * @param pObj URIobject to send from guest to the host.1631 */ 1632 static int vbglR3DnDGHSendURIObject(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)1591 * Utility function to send a transfer object from guest to the host. 1592 * 1593 * @returns IPRT status code. 1594 * @param pCtx DnD context to use. 1595 * @param pObj Transfer object to send from guest to the host. 1596 */ 1597 static int vbglR3DnDGHSendURIObject(PVBGLR3GUESTDNDCMDCTX pCtx, PDNDTRANSFEROBJECT pObj) 1633 1598 { 1634 1599 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); … … 1637 1602 int rc; 1638 1603 1639 switch (pObj->GetType()) 1640 { 1641 case DnDURIObject::Type_Directory: 1604 const DNDTRANSFEROBJTYPE enmType = DnDTransferObjectGetType(pObj); 1605 1606 switch (enmType) 1607 { 1608 case DNDTRANSFEROBJTYPE_DIRECTORY: 1642 1609 rc = vbglR3DnDGHSendDir(pCtx, pObj); 1643 1610 break; 1644 1611 1645 case D nDURIObject::Type_File:1612 case DNDTRANSFEROBJTYPE_FILE: 1646 1613 rc = vbglR3DnDGHSendFile(pCtx, pObj); 1647 1614 break; 1648 1615 1649 1616 default: 1650 AssertMsgFailed(("Object type %ld not implemented\n", pObj->GetType()));1617 AssertMsgFailed(("Object type %ld not implemented\n", enmType)); 1651 1618 rc = VERR_NOT_IMPLEMENTED; 1652 1619 break; … … 1682 1649 /** 1683 1650 * Guest -> Host 1684 * Utility function to send URI data from guest to the host. 1685 * 1686 * @returns IPRT status code. 1687 * @param pCtx DnD context to use. 1688 * @param pvData Block to URI data to send. 1689 * @param cbData Size (in bytes) of URI data to send. 1690 */ 1691 static int vbglR3DnDGHSendURIData(PVBGLR3GUESTDNDCMDCTX pCtx, const void *pvData, size_t cbData) 1692 { 1693 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1694 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 1695 AssertReturn(cbData, VERR_INVALID_PARAMETER); 1696 1697 RTCList<RTCString> lstPaths = 1698 RTCString((const char *)pvData, cbData).split("\r\n"); 1699 1700 /** @todo Add symlink support (DNDURILIST_FLAGS_RESOLVE_SYMLINKS) here. */ 1701 /** @todo Add lazy loading (DNDURILIST_FLAGS_LAZY) here. */ 1702 uint32_t fFlags = DNDURILIST_FLAGS_KEEP_OPEN; 1703 1704 DnDURIList lstURI; 1705 int rc = lstURI.AppendURIPathsFromList(lstPaths, fFlags); 1651 * Utility function to send transfer data from guest to the host. 1652 * 1653 * @returns IPRT status code. 1654 * @param pCtx DnD context to use. 1655 * @param pTransferList Dnd transfer list to send. 1656 */ 1657 static int vbglR3DnDGHSendTransferData(PVBGLR3GUESTDNDCMDCTX pCtx, PDNDTRANSFERLIST pTransferList) 1658 { 1659 AssertPtrReturn(pCtx,VERR_INVALID_POINTER); 1660 AssertPtrReturn(pTransferList, VERR_INVALID_POINTER); 1661 1662 /* 1663 * Send the (meta) data; in case of URIs it's the root entries of a 1664 * transfer list the host needs to know upfront to set up the drag'n drop operation. 1665 */ 1666 char *pszList = NULL; 1667 size_t cbList; 1668 int rc = DnDTransferListGetRoots(pTransferList, DNDTRANSFERLISTFMT_URI, &pszList, &cbList); 1669 if (RT_FAILURE(rc)) 1670 return rc; 1671 1672 void *pvURIList = (void *)pszList; 1673 uint32_t cbURLIist = (uint32_t)cbList; 1674 1675 /* The total size also contains the size of the meta data. */ 1676 uint64_t cbTotal = cbURLIist; 1677 cbTotal += DnDTransferListObjTotalBytes(pTransferList); 1678 1679 /* We're going to send a transfer list in text format. */ 1680 const char szMetaFmt[] = "text/uri-list"; 1681 const uint32_t cbMetaFmt = (uint32_t)strlen(szMetaFmt) + 1; /* Include termination. */ 1682 1683 VBOXDNDDATAHDR dataHdr; 1684 dataHdr.uFlags = 0; /* Flags not used yet. */ 1685 dataHdr.cbTotal = cbTotal; 1686 dataHdr.cbMeta = cbURLIist; 1687 dataHdr.pvMetaFmt = (void *)szMetaFmt; 1688 dataHdr.cbMetaFmt = cbMetaFmt; 1689 dataHdr.cObjects = DnDTransferListObjCount(pTransferList); 1690 1691 rc = vbglR3DnDGHSendDataInternal(pCtx, pvURIList, cbURLIist, &dataHdr); 1692 1706 1693 if (RT_SUCCESS(rc)) 1707 1694 { 1708 /* 1709 * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory 1710 * URI list the host needs to know upfront to set up the drag'n drop operation. 1711 */ 1712 RTCString strRootDest = lstURI.GetRootEntries(); 1713 if (strRootDest.isNotEmpty()) 1695 while (DnDTransferListObjCount(pTransferList)) 1714 1696 { 1715 void *pvURIList = (void *)strRootDest.c_str(); /* URI root list. */ 1716 uint32_t cbURLIist = (uint32_t)strRootDest.length() + 1; /* Include string termination. */ 1717 1718 /* The total size also contains the size of the meta data. */ 1719 uint64_t cbTotal = cbURLIist; 1720 cbTotal += lstURI.GetTotalBytes(); 1721 1722 /* We're going to send an URI list in text format. */ 1723 const char szMetaFmt[] = "text/uri-list"; 1724 const uint32_t cbMetaFmt = (uint32_t)strlen(szMetaFmt) + 1; /* Include termination. */ 1725 1726 VBOXDNDDATAHDR dataHdr; 1727 dataHdr.uFlags = 0; /* Flags not used yet. */ 1728 dataHdr.cbTotal = cbTotal; 1729 dataHdr.cbMeta = cbURLIist; 1730 dataHdr.pvMetaFmt = (void *)szMetaFmt; 1731 dataHdr.cbMetaFmt = cbMetaFmt; 1732 dataHdr.cObjects = lstURI.GetTotalCount(); 1733 1734 rc = vbglR3DnDGHSendDataInternal(pCtx, 1735 pvURIList, cbURLIist, &dataHdr); 1736 } 1737 else 1738 rc = VERR_INVALID_PARAMETER; 1739 } 1740 1741 if (RT_SUCCESS(rc)) 1742 { 1743 while (!lstURI.IsEmpty()) 1744 { 1745 DnDURIObject *pNextObj = lstURI.First(); 1746 1747 rc = vbglR3DnDGHSendURIObject(pCtx, pNextObj); 1697 PDNDTRANSFEROBJECT pObj = DnDTransferListObjGetFirst(pTransferList); 1698 1699 rc = vbglR3DnDGHSendURIObject(pCtx, pObj); 1748 1700 if (RT_FAILURE(rc)) 1749 1701 break; 1750 1702 1751 lstURI.RemoveFirst();1703 DnDTransferListObjRemoveFirst(pTransferList); 1752 1704 } 1705 1706 Assert(DnDTransferListObjCount(pTransferList) == 0); 1753 1707 } 1754 1708 … … 1779 1733 if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat))) 1780 1734 { 1781 /* Send file data. */ 1782 rc = vbglR3DnDGHSendURIData(pCtx, pvData, cbData); 1735 DNDTRANSFERLIST lstTransfer; 1736 rc = DnDTransferListInit(&lstTransfer, NULL /* pcszRootPathAbs */); 1737 if (RT_SUCCESS(rc)) 1738 { 1739 /** @todo Add symlink support (DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS) here. */ 1740 /** @todo Add lazy loading (DNDTRANSFERLIST_FLAGS_LAZY) here. */ 1741 const DNDTRANSFERLISTFLAGS fFlags = DNDTRANSFERLIST_FLAGS_KEEP_OPEN; 1742 1743 rc = DnDTransferListAppendPathsFromBuffer(&lstTransfer, DNDTRANSFERLISTFMT_NATIVE, (const char *)pvData, cbData, 1744 DND_PATH_SEPARATOR, fFlags); 1745 if (RT_SUCCESS(rc)) 1746 rc = vbglR3DnDGHSendTransferData(pCtx, &lstTransfer); 1747 DnDTransferListDestroy(&lstTransfer); 1748 } 1783 1749 } 1784 1750 else -
trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
r82968 r85371 549 549 int hgMove(uint32_t uPosX, uint32_t uPosY, VBOXDNDACTION dndActionDefault); 550 550 int hgDrop(uint32_t uPosX, uint32_t uPosY, VBOXDNDACTION dndActionDefault); 551 int hgDataReceive(PVBGLR3GUESTDNDMETADATA pMeta Data);551 int hgDataReceive(PVBGLR3GUESTDNDMETADATA pMeta); 552 552 553 553 /* X11 helpers. */ … … 1900 1900 * 1901 1901 * @returns IPRT status code. 1902 * @param pMeta DataPointer to meta data from host.1903 */ 1904 int DragInstance::hgDataReceive(PVBGLR3GUESTDNDMETADATA pMeta Data)1902 * @param pMeta Pointer to meta data from host. 1903 */ 1904 int DragInstance::hgDataReceive(PVBGLR3GUESTDNDMETADATA pMeta) 1905 1905 { 1906 1906 LogFlowThisFunc(("enmMode=%RU32, enmState=%RU32\n", m_enmMode, m_enmState)); 1907 LogFlowThisFunc(("enmMeta DataType=%RU32\n", pMetaData->enmType));1907 LogFlowThisFunc(("enmMetaType=%RU32\n", pMeta->enmType)); 1908 1908 1909 1909 if ( m_enmMode != HG … … 1913 1913 } 1914 1914 1915 if ( pMetaData->pvMeta == NULL 1916 || pMetaData->cbMeta == 0) 1917 { 1918 return VERR_INVALID_PARAMETER; 1919 } 1920 1921 int rc = VINF_SUCCESS; 1922 1923 const void *pvData = pMetaData->pvMeta; 1924 const uint32_t cbData = pMetaData->cbMeta; 1915 void *pvData = NULL; 1916 size_t cbData = 0; 1917 1918 int rc; 1919 1920 switch (pMeta->enmType) 1921 { 1922 case VBGLR3GUESTDNDMETADATATYPE_RAW: 1923 { 1924 AssertBreakStmt(pMeta->u.Raw.pvMeta != NULL, rc = VERR_INVALID_POINTER); 1925 pvData = pMeta->u.Raw.pvMeta; 1926 AssertBreakStmt(pMeta->u.Raw.cbMeta, rc = VERR_INVALID_PARAMETER); 1927 cbData = pMeta->u.Raw.cbMeta; 1928 1929 rc = VINF_SUCCESS; 1930 break; 1931 } 1932 1933 case VBGLR3GUESTDNDMETADATATYPE_URI_LIST: 1934 { 1935 VBClLogInfo(("URI transfer root directory is '%s'\n", DnDTransferListGetRootPathAbs(&pMeta->u.URI.Transfer))); 1936 1937 /* Note: The transfer list already has its root set to a temporary directory, so no need to set/add a new 1938 * path base here. */ 1939 rc = DnDTransferListGetRootsEx(&pMeta->u.URI.Transfer, DNDTRANSFERLISTFMT_NATIVE, NULL /* pszPathBase */, 1940 DND_PATH_SEPARATOR, (char **)&pvData, &cbData); 1941 break; 1942 } 1943 1944 default: 1945 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED); 1946 break; 1947 } 1948 1949 if (RT_FAILURE(rc)) 1950 return rc; 1925 1951 1926 1952 /* … … 1928 1954 * be on the guest, so proceed working on communicating with the target window. 1929 1955 */ 1930 VBClLogInfo("Received %RU32 bytes of URI listmeta data from host\n", cbData);1956 VBClLogInfo("Received %RU32 bytes of meta data from host\n", cbData); 1931 1957 1932 1958 /* Destroy any old data. */ -
trunk/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp
r85028 r85371 27 27 #include <iprt/err.h> 28 28 #include <iprt/file.h> 29 #include <iprt/mem.h> 29 30 #include <iprt/path.h> 30 31 #include <iprt/string.h> 31 32 32 33 33 #include <VBox/log.h> 34 34 35 DnDDroppedFiles::DnDDroppedFiles(void) 36 : m_fOpen(0) 37 , m_hDir(NULL) { } 38 39 DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 40 : m_fOpen(0) 41 , m_hDir(NULL) 42 { 43 OpenEx(pszPath, fFlags); 44 } 45 46 DnDDroppedFiles::~DnDDroppedFiles(void) 35 36 /********************************************************************************************************************************* 37 * Prototypes * 38 *********************************************************************************************************************************/ 39 static int dndDroppedFilesCloseInternal(PDNDDROPPEDFILES pDF); 40 41 42 int DnDDroppedFilesInit(PDNDDROPPEDFILES pDF, 43 const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 44 { 45 pDF->m_fOpen = 0; 46 pDF->m_hDir = NIL_RTDIR; 47 48 return DnDDroppedFilesOpenEx(pDF, pszPath, fFlags); 49 } 50 51 void DnDDroppedFilesDestroy(PDNDDROPPEDFILES pDF) 47 52 { 48 53 /* Only make sure to not leak any handles and stuff, don't delete any 49 54 * directories / files here. */ 50 closeInternal();55 dndDroppedFilesCloseInternal(pDF); 51 56 } 52 57 … … 57 62 * @param pszFile Path of file entry to add. 58 63 */ 59 int DnDDroppedFiles ::AddFile(const char *pszFile)64 int DnDDroppedFilesAddFile(PDNDDROPPEDFILES pDF, const char *pszFile) 60 65 { 61 66 AssertPtrReturn(pszFile, VERR_INVALID_POINTER); 62 67 63 if (!this->m_lstFiles.contains(pszFile)) 64 this->m_lstFiles.append(pszFile); 65 return VINF_SUCCESS; 68 PDNDDROPPEDFILESENTRY pEntry = (PDNDDROPPEDFILESENTRY)RTMemAlloc(sizeof(DNDDROPPEDFILESENTRY)); 69 if (!pEntry) 70 return VERR_NO_MEMORY; 71 72 pEntry->pszPath = RTStrDup(pszFile); 73 if (pEntry->pszPath) 74 { 75 RTListAppend(&pDF->m_lstFiles, &pEntry->Node); 76 return VINF_SUCCESS; 77 } 78 79 RTMemFree(pEntry); 80 return VERR_NO_MEMORY; 66 81 } 67 82 … … 73 88 * @param pszDir Path of directory entry to add. 74 89 */ 75 int DnDDroppedFiles ::AddDir(const char *pszDir)90 int DnDDroppedFilesAddDir(PDNDDROPPEDFILES pDF, const char *pszDir) 76 91 { 77 92 AssertPtrReturn(pszDir, VERR_INVALID_POINTER); 78 93 79 if (!this->m_lstDirs.contains(pszDir)) 80 this->m_lstDirs.append(pszDir); 81 return VINF_SUCCESS; 94 PDNDDROPPEDFILESENTRY pEntry = (PDNDDROPPEDFILESENTRY)RTMemAlloc(sizeof(DNDDROPPEDFILESENTRY)); 95 if (!pEntry) 96 return VERR_NO_MEMORY; 97 98 pEntry->pszPath = RTStrDup(pszDir); 99 if (pEntry->pszPath) 100 { 101 RTListAppend(&pDF->m_lstDirs, &pEntry->Node); 102 return VINF_SUCCESS; 103 } 104 105 RTMemFree(pEntry); 106 return VERR_NO_MEMORY; 82 107 } 83 108 … … 87 112 * @returns VBox status code. 88 113 */ 89 int DnDDroppedFiles::closeInternal(void)114 static int dndDroppedFilesCloseInternal(PDNDDROPPEDFILES pDF) 90 115 { 91 116 int rc; 92 if ( this->m_hDir != NULL)93 { 94 rc = RTDirClose( this->m_hDir);117 if (pDF->m_hDir != NULL) 118 { 119 rc = RTDirClose(pDF->m_hDir); 95 120 if (RT_SUCCESS(rc)) 96 this->m_hDir = NULL;121 pDF->m_hDir = NULL; 97 122 } 98 123 else … … 108 133 * @returns VBox status code. 109 134 */ 110 int DnDDroppedFiles ::Close(void)111 { 112 return closeInternal();135 int DnDDroppedFilesClose(PDNDDROPPEDFILES pDF) 136 { 137 return dndDroppedFilesCloseInternal(pDF); 113 138 } 114 139 … … 118 143 * @returns Pointer to absolute path of the dropped files directory. 119 144 */ 120 const char *DnDDroppedFiles ::GetDirAbs(void) const121 { 122 return this->m_strPathAbs.c_str();145 const char *DnDDroppedFilesGetDirAbs(PDNDDROPPEDFILES pDF) 146 { 147 return pDF->pszPathAbs; 123 148 } 124 149 … … 128 153 * @returns \c true if open, \c false if not. 129 154 */ 130 bool DnDDroppedFiles ::IsOpen(void) const131 { 132 return ( this->m_hDir != NULL);155 bool DnDDroppedFilesIsOpen(PDNDDROPPEDFILES pDF) 156 { 157 return (pDF->m_hDir != NULL); 133 158 } 134 159 … … 140 165 * @param fFlags Dropped files flags to use for this directory. 141 166 */ 142 int DnDDroppedFiles::OpenEx(const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 167 int DnDDroppedFilesOpenEx(PDNDDROPPEDFILES pDF, 168 const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */) 143 169 { 144 170 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); … … 179 205 } 180 206 181 rc = DnDPathSanitize (szTime, sizeof(szTime));207 rc = DnDPathSanitizeFileName(szTime, sizeof(szTime)); 182 208 if (RT_FAILURE(rc)) 183 209 break; … … 195 221 if (RT_SUCCESS(rc)) 196 222 { 197 this->m_hDir= hDir;198 this->m_strPathAbs = szDropDir;199 this->m_fOpen= fFlags;223 pDF->m_hDir = hDir; 224 pDF->pszPathAbs = szDropDir; 225 pDF->m_fOpen = fFlags; 200 226 } 201 227 } … … 213 239 * @param fFlags Dropped files flags to use for this directory. 214 240 */ 215 int DnDDroppedFiles ::OpenTemp(DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)241 int DnDDroppedFilesOpenTemp(PDNDDROPPEDFILES pDF, DNDURIDROPPEDFILEFLAGS fFlags) 216 242 { 217 243 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */ … … 225 251 int rc = RTPathTemp(szTemp, sizeof(szTemp)); 226 252 if (RT_SUCCESS(rc)) 227 rc = OpenEx(szTemp, fFlags); 228 229 return rc; 253 rc = DnDDroppedFilesOpenEx(pDF, szTemp, fFlags); 254 255 return rc; 256 } 257 258 static void dndDroppedFilesEntryFree(PDNDDROPPEDFILESENTRY pEntry) 259 { 260 if (!pEntry) 261 return; 262 RTStrFree(pEntry->pszPath); 263 RTListNodeRemove(&pEntry->Node); 264 RTMemFree(pEntry); 265 } 266 267 static void dndDroppedFilesResetList(PRTLISTANCHOR pListAnchor) 268 { 269 PDNDDROPPEDFILESENTRY pEntryCur, pEntryNext; 270 RTListForEachSafe(pListAnchor, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node) 271 dndDroppedFilesEntryFree(pEntryCur); 272 Assert(RTListIsEmpty(pListAnchor)); 230 273 } 231 274 … … 237 280 * or just clear the internal references. 238 281 */ 239 int DnDDroppedFiles ::Reset(bool fDelete)240 { 241 int rc = closeInternal();282 int DnDDroppedFilesReset(PDNDDROPPEDFILES pDF, bool fDelete) 283 { 284 int rc = dndDroppedFilesCloseInternal(pDF); 242 285 if (RT_SUCCESS(rc)) 243 286 { 244 287 if (fDelete) 245 288 { 246 rc = Rollback();289 rc = DnDDroppedFilesRollback(pDF); 247 290 } 248 291 else 249 292 { 250 this->m_lstDirs.clear();251 this->m_lstFiles.clear();293 dndDroppedFilesResetList(&pDF->m_lstDirs); 294 dndDroppedFilesResetList(&pDF->m_lstFiles); 252 295 } 253 296 } … … 262 305 * @returns VBox status code, or VERR_NOT_FOUND if the dropped files directory has not been opened before. 263 306 */ 264 int DnDDroppedFiles ::Reopen(void)265 { 266 if ( this->m_strPathAbs.isEmpty())307 int DnDDroppedFilesReopen(PDNDDROPPEDFILES pDF) 308 { 309 if (!pDF->pszPathAbs) 267 310 return VERR_NOT_FOUND; 268 311 269 return OpenEx(this->m_strPathAbs.c_str(), this->m_fOpen);312 return DnDDroppedFilesOpenEx(pDF, pDF->pszPathAbs, pDF->m_fOpen); 270 313 } 271 314 … … 276 319 * @returns VBox status code. 277 320 */ 278 int DnDDroppedFiles ::Rollback(void)279 { 280 if ( this->m_strPathAbs.isEmpty())321 int DnDDroppedFilesRollback(PDNDDROPPEDFILES pDF) 322 { 323 if (!pDF->pszPathAbs) 281 324 return VINF_SUCCESS; 282 325 … … 287 330 * anything recursive here! Steam (tm) knows best ... :-) */ 288 331 int rc2; 289 for (size_t i = 0; i < this->m_lstFiles.size(); i++) 290 { 291 rc2 = RTFileDelete(this->m_lstFiles.at(i).c_str()); 332 PDNDDROPPEDFILESENTRY pEntryCur, pEntryNext; 333 RTListForEachSafe(&pDF->m_lstFiles, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node) 334 { 335 rc2 = RTFileDelete(pEntryCur->pszPath); 292 336 if (RT_SUCCESS(rc2)) 293 this->m_lstFiles.removeAt(i);337 dndDroppedFilesEntryFree(pEntryCur); 294 338 else if (RT_SUCCESS(rc)) 295 339 rc = rc2; … … 297 341 } 298 342 299 for (size_t i = 0; i < this->m_lstDirs.size(); i++)300 { 301 rc2 = RTDirRemove( this->m_lstDirs.at(i).c_str());343 RTListForEachSafe(&pDF->m_lstDirs, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node) 344 { 345 rc2 = RTDirRemove(pEntryCur->pszPath); 302 346 if (RT_SUCCESS(rc2)) 303 this->m_lstDirs.removeAt(i);347 dndDroppedFilesEntryFree(pEntryCur); 304 348 else if (RT_SUCCESS(rc)) 305 349 rc = rc2; … … 309 353 if (RT_SUCCESS(rc)) 310 354 { 311 Assert(this->m_lstFiles.isEmpty()); 312 Assert(this->m_lstDirs.isEmpty()); 313 314 rc2 = closeInternal(); 355 rc2 = dndDroppedFilesCloseInternal(pDF); 315 356 if (RT_SUCCESS(rc2)) 316 357 { 317 358 /* Try to remove the empty root dropped files directory as well. 318 359 * Might return VERR_DIR_NOT_EMPTY or similar. */ 319 rc2 = RTDirRemove( this->m_strPathAbs.c_str());360 rc2 = RTDirRemove(pDF->pszPathAbs); 320 361 } 321 362 if (RT_SUCCESS(rc)) -
trunk/src/VBox/GuestHost/DragAndDrop/DnDMIME.cpp
r82968 r85371 35 35 bool DnDMIMENeedsDropDir(const char *pcszFormat, size_t cchFormatMax) 36 36 { 37 bool fNeedsDropDir = false; 38 if (!RTStrNICmp(pcszFormat, "text/uri-list", cchFormatMax)) /** @todo Add "x-special/gnome-icon-list"? */ 39 fNeedsDropDir = true; 40 41 return fNeedsDropDir; 37 return DnDMIMEHasFileURLs(pcszFormat, cchFormatMax); 42 38 } 43 39 -
trunk/src/VBox/GuestHost/DragAndDrop/DnDPath.cpp
r85028 r85371 28 28 #include <iprt/path.h> 29 29 #include <iprt/string.h> 30 31 32 /** 33 * Sanitizes a path so that unsupported characters will be replaced by an underscore ("_"). 30 #include <iprt/uri.h> 31 32 33 /** 34 * Sanitizes the file name portion of a path so that unsupported characters will be replaced by an underscore ("_"). 34 35 * 35 36 * @return IPRT status code. 36 * @param psz Path Pathto sanitize.37 * @param cb Path Size (in bytes) of pathto sanitize.38 */ 39 int DnDPathSanitize (char *pszPath, size_t cbPath)40 { 41 if (!psz Path) /* No path given? Bail out early. */37 * @param pszFileName File name to sanitize. 38 * @param cbFileName Size (in bytes) of file name to sanitize. 39 */ 40 int DnDPathSanitizeFileName(char *pszFileName, size_t cbFileName) 41 { 42 if (!pszFileName) /* No path given? Bail out early. */ 42 43 return VINF_SUCCESS; 43 44 44 AssertReturn(cb Path, VERR_INVALID_PARAMETER);45 AssertReturn(cbFileName, VERR_INVALID_PARAMETER); 45 46 46 47 int rc = VINF_SUCCESS; 47 48 #ifdef RT_OS_WINDOWS 48 RT_NOREF1(cb Path);49 RT_NOREF1(cbFileName); 49 50 /* Replace out characters not allowed on Windows platforms, put in by RTTimeSpecToString(). */ 50 51 /** @todo Use something like RTPathSanitize() if available later some time. */ … … 62 63 }; 63 64 64 ssize_t cReplaced = RTStrPurgeComplementSet(psz Path, s_uszValidRangePairs, '_' /* chReplacement */);65 ssize_t cReplaced = RTStrPurgeComplementSet(pszFileName, s_uszValidRangePairs, '_' /* chReplacement */); 65 66 if (cReplaced < 0) 66 67 rc = VERR_INVALID_UTF8_ENCODING; 67 68 #else 68 RT_NOREF2(psz Path, cbPath);69 RT_NOREF2(pszFileName, cbFileName); 69 70 #endif 70 71 return rc; … … 73 74 /** 74 75 * Validates whether a given path matches our set of rules or not. 76 * 77 * Rules: 78 * - An empty path is allowed. 79 * - Dot components ("." or "..") are forbidden. 80 * - If \a fMustExist is \c true, the path either has to be a file or a directory and must exist. 81 * - Symbolic links are forbidden. 75 82 * 76 83 * @returns VBox status code. … … 81 88 int DnDPathValidate(const char *pcszPath, bool fMustExist) 82 89 { 90 if (!pcszPath) 91 return VERR_INVALID_POINTER; 92 83 93 int rc = VINF_SUCCESS; 84 85 if (!strlen(pcszPath))86 rc = VERR_INVALID_PARAMETER;87 94 88 95 if ( RT_SUCCESS(rc) … … 136 143 AssertReturn(!(fFlags & ~DNDPATHCONVERT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 137 144 138 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) 139 if (fFlags & DNDPATHCONVERT_FLAGS_TO_NATIVE) 140 RTPathChangeToDosSlashes(pszPath, true); 145 if (fFlags & DNDPATHCONVERT_FLAGS_TO_DOS) 146 RTPathChangeToDosSlashes(pszPath, true /* fForce */); 141 147 else 142 #else143 RT_NOREF(fFlags);144 #endif145 {146 148 RTPathChangeToUnixSlashes(pszPath, true /* fForce */); 147 }148 149 149 150 return VINF_SUCCESS; 150 151 } 151 152 153 /** 154 * Rebases an absolute path from an old path base to a new path base. 155 * Note: Does *not* do any path conversion. 156 * 157 * @return IPRT status code. 158 * @param pcszPath Path to rebase. 159 * @param strBaseOld Old base path to rebase from. Optional and can be NULL. 160 * @param strBaseNew New base path to rebase to. 161 * @param ppszPath Where to store the allocated rebased path on success. Needs to be free'd with RTStrFree(). 162 */ 163 int DnDPathRebase(const char *pcszPath, const char *pcszBaseOld, const char *pcszBaseNew, 164 char **ppszPath) 165 { 166 AssertPtrReturn(pcszPath, VERR_INVALID_POINTER); 167 AssertPtrReturn(pcszBaseOld, VERR_INVALID_POINTER); 168 AssertPtrReturn(pcszBaseNew, VERR_INVALID_POINTER); 169 AssertPtrReturn(ppszPath, VERR_INVALID_POINTER); 170 171 char szPath[RTPATH_MAX]; 172 173 /* Do we need to see if the given path is part of the old base? */ 174 size_t idxBase; 175 if ( pcszBaseOld 176 && RTPathStartsWith(pcszPath, pcszBaseOld)) 177 { 178 idxBase = strlen(pcszBaseOld); 179 } 180 else 181 idxBase = 0; 182 183 int rc = RTStrCopy(szPath, sizeof(szPath), pcszBaseNew); 184 if (RT_SUCCESS(rc)) 185 { 186 rc = RTPathAppend(szPath, sizeof(szPath), &pcszPath[idxBase]); 187 if (RT_SUCCESS(rc)) 188 rc = DnDPathValidate(szPath, false /* fMustExist */); 189 } 190 191 if (RT_SUCCESS(rc)) 192 { 193 char *pszPath = RTStrDup(szPath); 194 if (pszPath) 195 *ppszPath = pszPath; 196 else 197 rc = VERR_NO_MEMORY; 198 } 199 200 return rc; 201 } 202 -
trunk/src/VBox/GuestHost/DragAndDrop/DnDTransferList.cpp
r85369 r85371 1 1 /* $Id$ */ 2 2 /** @file 3 * DnD - URI list class.3 * DnD - transfer list implemenation. 4 4 */ 5 5 … … 27 27 #include <iprt/file.h> 28 28 #include <iprt/fs.h> 29 #include <iprt/mem.h> 29 30 #include <iprt/path.h> 30 31 #include <iprt/string.h> … … 35 36 36 37 37 DnDURIList::DnDURIList(void) 38 : m_cTotal(0) 39 , m_cbTotal(0) 40 { 41 } 42 43 DnDURIList::~DnDURIList(void) 44 { 45 Clear(); 46 } 47 48 int DnDURIList::addEntry(const char *pcszSource, const char *pcszTarget, DNDURILISTFLAGS fFlags) 49 { 50 AssertPtrReturn(pcszSource, VERR_INVALID_POINTER); 51 AssertPtrReturn(pcszTarget, VERR_INVALID_POINTER); 52 53 LogFlowFunc(("pcszSource=%s, pcszTarget=%s, fFlags=0x%x\n", pcszSource, pcszTarget, fFlags)); 54 55 RTFSOBJINFO objInfo; 56 int rc = RTPathQueryInfo(pcszSource, &objInfo, RTFSOBJATTRADD_NOTHING); 38 /********************************************************************************************************************************* 39 * Prototypes * 40 *********************************************************************************************************************************/ 41 static int dndTransferListSetRootPath(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs); 42 43 static int dndTransferListRootAdd(PDNDTRANSFERLIST pList, const char *pcszRoot); 44 static void dndTransferListRootFree(PDNDTRANSFERLIST pList, PDNDTRANSFERLISTROOT pRootObj); 45 46 static int dndTransferListObjAdd(PDNDTRANSFERLIST pList, const char *pcszSrcAbs, RTFMODE fMode, DNDTRANSFERLISTFLAGS fFlags); 47 static void dndTransferListObjFree(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pLstObj); 48 49 50 /** The size of the directory entry buffer we're using. */ 51 #define DNDTRANSFERLIST_DIRENTRY_BUF_SIZE (sizeof(RTDIRENTRYEX) + RTPATH_MAX) 52 53 54 /** 55 * Initializes a transfer list. 56 * 57 * @returns VBox status code. 58 * @param pList Transfer list to initialize. 59 * @param pcszRootPathAbs Absolute root path to use for this list. Optional and can be NULL. 60 */ 61 int DnDTransferListInit(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs) 62 { 63 AssertPtrReturn(pList, VERR_INVALID_POINTER); 64 /* pcszRootPathAbs is optional. */ 65 66 if (!strlen(pcszRootPathAbs)) 67 return VERR_INVALID_PARAMETER; 68 69 if (pList->pszPathRootAbs) 70 return VERR_WRONG_ORDER; 71 72 pList->pszPathRootAbs = NULL; 73 74 RTListInit(&pList->lstRoot); 75 pList->cRoots = 0; 76 77 RTListInit(&pList->lstObj); 78 pList->cObj = 0; 79 pList->cbObjTotal = 0; 80 81 if (pcszRootPathAbs) 82 return dndTransferListSetRootPath(pList, pcszRootPathAbs); 83 84 return VINF_SUCCESS; 85 } 86 87 /** 88 * Destroys a transfer list. 89 * 90 * @param pList Transfer list to destroy. 91 */ 92 void DnDTransferListDestroy(PDNDTRANSFERLIST pList) 93 { 94 if (!pList) 95 return; 96 97 DnDTransferListReset(pList); 98 99 RTStrFree(pList->pszPathRootAbs); 100 pList->pszPathRootAbs = NULL; 101 } 102 103 /** 104 * Resets a transfer list. 105 * 106 * Note: Does *not* clear the root path! 107 * 108 * @param pList Transfer list to clear. 109 */ 110 void DnDTransferListReset(PDNDTRANSFERLIST pList) 111 { 112 AssertPtrReturnVoid(pList); 113 114 /* Note: This does not clear the root path! */ 115 116 PDNDTRANSFERLISTROOT pRootCur, pRootNext; 117 RTListForEachSafe(&pList->lstRoot, pRootCur, pRootNext, DNDTRANSFERLISTROOT, Node) 118 dndTransferListRootFree(pList, pRootCur); 119 Assert(RTListIsEmpty(&pList->lstRoot)); 120 121 PDNDTRANSFEROBJECT pObjCur, pObjNext; 122 RTListForEachSafe(&pList->lstObj, pObjCur, pObjNext, DNDTRANSFEROBJECT, Node) 123 dndTransferListObjFree(pList, pObjCur); 124 Assert(RTListIsEmpty(&pList->lstObj)); 125 126 Assert(pList->cRoots == 0); 127 Assert(pList->cObj == 0); 128 129 pList->cbObjTotal = 0; 130 } 131 132 /** 133 * Adds a single transfer object entry to a transfer List. 134 * 135 * @returns VBox status code. 136 * @param pList Transfer list to add entry to. 137 * @param pcszSrcAbs Absolute source path (local) to use. 138 * @param fMode File mode of entry to add. 139 * @param fFlags Transfer list flags to use for appending. 140 */ 141 static int dndTransferListObjAdd(PDNDTRANSFERLIST pList, const char *pcszSrcAbs, RTFMODE fMode, DNDTRANSFERLISTFLAGS fFlags) 142 { 143 AssertPtrReturn(pList, VERR_INVALID_POINTER); 144 AssertPtrReturn(pcszSrcAbs, VERR_INVALID_POINTER); 145 146 LogFlowFunc(("pcszSrcAbs=%s, fMode=%#x, fFlags=0x%x\n", pcszSrcAbs, fMode, fFlags)); 147 148 int rc = VINF_SUCCESS; 149 150 if ( !RTFS_IS_FILE(fMode) 151 && !RTFS_IS_DIRECTORY(fMode)) 152 /** @todo Symlinks not allowed. */ 153 { 154 rc = VERR_NOT_SUPPORTED; 155 } 156 57 157 if (RT_SUCCESS(rc)) 58 158 { 59 if (RTFS_IS_FILE(objInfo.Attr.fMode)) 60 { 61 LogFlowFunc(("File '%s' -> '%s' (%RU64 bytes, file mode 0x%x)\n", 62 pcszSource, pcszTarget, (uint64_t)objInfo.cbObject, objInfo.Attr.fMode)); 63 64 DnDURIObject *pObjFile = new DnDURIObject(DnDURIObject::Type_File, pcszSource); 65 if (pObjFile) 159 /* Calculate the path to add as the destination path to our URI object. */ 160 const size_t idxPathToAdd = strlen(pList->pszPathRootAbs); 161 AssertReturn(strlen(pcszSrcAbs) > idxPathToAdd, VERR_INVALID_PARAMETER); /* Should never happen (tm). */ 162 163 PDNDTRANSFEROBJECT pObj = (PDNDTRANSFEROBJECT)RTMemAllocZ(sizeof(DNDTRANSFEROBJECT)); 164 if (pObj) 165 { 166 pObj = (PDNDTRANSFEROBJECT)RTMemAllocZ(sizeof(DNDTRANSFEROBJECT)); 167 if (pObj) 66 168 { 67 /** @todo Add a standard fOpen mode for this list. */ 68 rc = pObjFile->Open(RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); 169 const bool fIsFile = RTFS_IS_FILE(fMode); 170 171 rc = DnDTransferObjectInit(pObj, fIsFile ? DNDTRANSFEROBJTYPE_FILE : DNDTRANSFEROBJTYPE_DIRECTORY, 172 pList->pszPathRootAbs, &pcszSrcAbs[idxPathToAdd]); 69 173 if (RT_SUCCESS(rc)) 70 174 { 71 m_lstTree.append(pObjFile); 72 73 m_cTotal++; 74 m_cbTotal += pObjFile->GetSize(); 75 76 if (!(fFlags & DNDURILIST_FLAGS_KEEP_OPEN)) /* Shall we keep the file open while being added to this list? */ 77 pObjFile->Close(); 175 if (fIsFile) 176 rc = DnDTransferObjectOpen(pObj, 177 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, /** @todo Add a standard fOpen mode for this list. */ 178 0 /* fMode */, DNDTRANSFEROBJECT_FLAGS_NONE); 179 if (RT_SUCCESS(rc)) 180 { 181 RTListAppend(&pList->lstObj, &pObj->Node); 182 183 pList->cObj++; 184 if (fIsFile) 185 pList->cbObjTotal += DnDTransferObjectGetSize(pObj); 186 187 if ( fIsFile 188 && !(fFlags & DNDTRANSFERLIST_FLAGS_KEEP_OPEN)) /* Shall we keep the file open while being added to this list? */ 189 DnDTransferObjectClose(pObj); 190 } 191 192 if (RT_FAILURE(rc)) 193 DnDTransferObjectDestroy(pObj); 78 194 } 79 195 80 196 if (RT_FAILURE(rc)) 81 delete pObjFile;197 RTMemFree(pObj); 82 198 } 83 199 else 84 200 rc = VERR_NO_MEMORY; 85 } 86 else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 87 { 88 LogFlowFunc(("Directory '%s' -> '%s' (file mode 0x%x)\n", pcszSource, pcszTarget, objInfo.Attr.fMode)); 89 90 DnDURIObject *pObjDir = new DnDURIObject(DnDURIObject::Type_Directory, pcszSource); 91 if (pObjDir) 201 202 if (RT_FAILURE(rc)) 203 RTMemFree(pObj); 204 } 205 else 206 rc = VERR_NO_MEMORY; 207 } 208 209 if (RT_FAILURE(rc)) 210 LogRel(("DnD: Adding entry '%s' of type %#x failed with rc=%Rrc\n", pcszSrcAbs, fMode & RTFS_TYPE_MASK, rc)); 211 212 LogFlowFuncLeaveRC(rc); 213 return rc; 214 } 215 216 /** 217 * Frees an internal DnD transfer list object. 218 * 219 * @param pList Transfer list to free object for. 220 * @param pLstObj transfer list object to free. The pointer will be invalid after calling. 221 */ 222 static void dndTransferListObjFree(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pObj) 223 { 224 if (!pObj) 225 return; 226 227 DnDTransferObjectDestroy(pObj); 228 RTListNodeRemove(&pObj->Node); 229 RTMemFree(pObj); 230 231 AssertReturnVoid(pList->cObj); 232 pList->cObj--; 233 } 234 235 /** 236 * Helper routine for handling adding sub directories. 237 * 238 * @return IPRT status code. 239 * @param pList transfer list to add found entries to. 240 * @param pszDir Pointer to the directory buffer. 241 * @param cchDir The length of pszDir in pszDir. 242 * @param pDirEntry Pointer to the directory entry. 243 * @param fFlags Flags of type DNDTRANSFERLISTFLAGS. 244 */ 245 static int dndTransferListAppendPathRecursiveSub(PDNDTRANSFERLIST pList, 246 char *pszDir, size_t cchDir, PRTDIRENTRYEX pDirEntry, 247 DNDTRANSFERLISTFLAGS fFlags) 248 249 { 250 Assert(cchDir > 0); Assert(pszDir[cchDir] == '\0'); 251 252 /* Make sure we've got some room in the path, to save us extra work further down. */ 253 if (cchDir + 3 >= RTPATH_MAX) 254 return VERR_BUFFER_OVERFLOW; 255 256 /* Open directory. */ 257 RTDIR hDir; 258 int rc = RTDirOpen(&hDir, pszDir); 259 if (RT_FAILURE(rc)) 260 return rc; 261 262 /* Ensure we've got a trailing slash (there is space for it see above). */ 263 if (!RTPATH_IS_SEP(pszDir[cchDir - 1])) 264 { 265 pszDir[cchDir++] = RTPATH_SLASH; 266 pszDir[cchDir] = '\0'; 267 } 268 269 LogFlowFunc(("pszDir=%s\n", pszDir)); 270 271 /* 272 * Process the files and subdirs. 273 */ 274 for (;;) 275 { 276 /* Get the next directory. */ 277 size_t cbDirEntry = DNDTRANSFERLIST_DIRENTRY_BUF_SIZE; 278 rc = RTDirReadEx(hDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); 279 if (RT_FAILURE(rc)) 280 break; 281 282 /* Check length. */ 283 if (pDirEntry->cbName + cchDir + 3 >= RTPATH_MAX) 284 { 285 rc = VERR_BUFFER_OVERFLOW; 286 break; 287 } 288 289 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) 290 { 291 case RTFS_TYPE_SYMLINK: 92 292 { 93 m_lstTree.append(pObjDir); 94 95 /** @todo Add DNDURILIST_FLAGS_KEEP_OPEN handling? */ 96 m_cTotal++; 293 if (!(fFlags & DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS)) 294 break; 295 RT_FALL_THRU(); 296 } 297 case RTFS_TYPE_DIRECTORY: 298 { 299 if (RTDirEntryExIsStdDotLink(pDirEntry)) 300 continue; 301 302 memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1); 303 int rc2 = dndTransferListAppendPathRecursiveSub(pList, pszDir, cchDir + pDirEntry->cbName, pDirEntry, fFlags); 304 if (RT_SUCCESS(rc)) 305 rc = rc2; 306 break; 307 } 308 309 case RTFS_TYPE_FILE: 310 { 311 memcpy(&pszDir[cchDir], pDirEntry->szName, pDirEntry->cbName + 1); 312 rc = dndTransferListObjAdd(pList, pszDir, pDirEntry->Info.Attr.fMode, fFlags); 313 break; 314 } 315 316 default: 317 { 318 319 break; 320 } 321 } 322 } 323 324 if (rc == VERR_NO_MORE_FILES) /* Done reading current directory? */ 325 { 326 rc = VINF_SUCCESS; 327 } 328 else if (RT_FAILURE(rc)) 329 LogRel(("DnD: Error while adding files recursively, rc=%Rrc\n", rc)); 330 331 int rc2 = RTDirClose(hDir); 332 if (RT_FAILURE(rc2)) 333 { 334 if (RT_SUCCESS(rc)) 335 rc = rc2; 336 } 337 338 return rc; 339 } 340 341 /** 342 * Appends a native system path recursively by adding these entries as transfer objects. 343 * 344 * @returns VBox status code. 345 * @param pList Transfer list to add found entries to. 346 * @param pcszPathAbs Absolute path to add. 347 * @param fFlags Flags of type DNDTRANSFERLISTFLAGS. 348 */ 349 static int dndTransferListAppendPathNativeRecursive(PDNDTRANSFERLIST pList, 350 const char *pcszPathAbs, DNDTRANSFERLISTFLAGS fFlags) 351 { 352 char szPathAbs[RTPATH_MAX]; 353 int rc = RTStrCopy(szPathAbs, sizeof(szPathAbs), pcszPathAbs); 354 if (RT_FAILURE(rc)) 355 return rc; 356 357 union 358 { 359 uint8_t abPadding[DNDTRANSFERLIST_DIRENTRY_BUF_SIZE]; 360 RTDIRENTRYEX DirEntry; 361 } uBuf; 362 const size_t cchPathAbs = strlen(szPathAbs); 363 if (!cchPathAbs) 364 return VINF_SUCCESS; 365 return dndTransferListAppendPathRecursiveSub(pList, szPathAbs, cchPathAbs, &uBuf.DirEntry, fFlags); 366 } 367 368 static int dndTransferListAppendPathNative(PDNDTRANSFERLIST pList, const char *pcszPath, DNDTRANSFERLISTFLAGS fFlags) 369 { 370 /* We don't want to have a relative directory here. */ 371 if (!RTPathStartsWithRoot(pcszPath)) 372 return VERR_INVALID_PARAMETER; 373 374 int rc = DnDPathValidate(pcszPath, false /* fMustExist */); 375 if (RT_FAILURE(rc)) 376 return rc; 377 378 char szPathAbs[RTPATH_MAX]; 379 rc = RTStrCopy(szPathAbs, sizeof(szPathAbs), pcszPath); 380 if (RT_FAILURE(rc)) 381 return rc; 382 383 size_t cchPathAbs = RTStrNLen(szPathAbs, sizeof(szPathAbs)); 384 AssertReturn(cchPathAbs, VERR_INVALID_PARAMETER); 385 386 /* Convert path to transport style. */ 387 rc = DnDPathConvert(szPathAbs, sizeof(szPathAbs), DNDPATHCONVERT_FLAGS_TRANSPORT); 388 if (RT_SUCCESS(rc)) 389 { 390 /* Make sure the path has the same root path as our list. */ 391 if (RTPathStartsWith(szPathAbs, pList->pszPathRootAbs)) 392 { 393 RTDIR hDir; 394 rc = RTDirOpen(&hDir, szPathAbs); 395 if (RT_SUCCESS(rc)) 396 { 397 for (;;) 398 { 399 /* Get the next directory. */ 400 RTDIRENTRYEX dirEntry; 401 rc = RTDirReadEx(hDir, &dirEntry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK /** @todo No symlinks yet. */); 402 if (RT_SUCCESS(rc)) 403 { 404 if (RTDirEntryExIsStdDotLink(&dirEntry)) 405 continue; 406 407 /* Check length. */ 408 if (dirEntry.cbName + cchPathAbs + 3 >= sizeof(szPathAbs)) 409 { 410 rc = VERR_BUFFER_OVERFLOW; 411 break; 412 } 413 414 /* Append the directory entry to our absolute path. */ 415 memcpy(&szPathAbs[cchPathAbs], dirEntry.szName, dirEntry.cbName + 1); 416 417 LogFlowFunc(("szName=%s, szPathAbs=%s\n", dirEntry.szName, szPathAbs)); 418 419 switch (dirEntry.Info.Attr.fMode & RTFS_TYPE_MASK) 420 { 421 case RTFS_TYPE_DIRECTORY: 422 { 423 rc = dndTransferListAppendPathNativeRecursive(pList, szPathAbs, fFlags); 424 break; 425 } 426 427 case RTFS_TYPE_FILE: 428 { 429 rc = dndTransferListObjAdd(pList, szPathAbs, dirEntry.Info.Attr.fMode, fFlags); 430 break; 431 } 432 433 default: 434 rc = VERR_NOT_SUPPORTED; 435 break; 436 } 437 438 if (RT_SUCCESS(rc)) 439 rc = dndTransferListRootAdd(pList, dirEntry.szName); 440 } 441 else if (rc == VERR_NO_MORE_FILES) 442 { 443 rc = VINF_SUCCESS; 444 break; 445 } 446 else 447 break; 448 449 if (RT_FAILURE(rc)) 450 break; 451 } 452 } 453 } 454 else 455 rc = VERR_INVALID_PARAMETER; 456 } 457 458 if (RT_FAILURE(rc)) 459 LogRel(("DnD: Adding native path '%s' failed with rc=%Rrc\n", pcszPath, rc)); 460 461 return rc; 462 } 463 464 static int dndTransferListAppendPathURI(PDNDTRANSFERLIST pList, const char *pcszPath, DNDTRANSFERLISTFLAGS fFlags) 465 { 466 RT_NOREF(fFlags); 467 468 /* Query the path component of a file URI. If this hasn't a 469 * file scheme, NULL is returned. */ 470 char *pszFilePath; 471 int rc = RTUriFilePathEx(pcszPath, RTPATH_STR_F_STYLE_UNIX, &pszFilePath, 0 /*cbPath*/, NULL /*pcchPath*/); 472 if (RT_SUCCESS(rc)) 473 { 474 LogFlowFunc(("pcszPath=%s -> pszFilePath=%s\n", pcszPath, pszFilePath)); 475 rc = dndTransferListRootAdd(pList, pszFilePath); 476 RTStrFree(pszFilePath); 477 478 } 479 480 if (RT_FAILURE(rc)) 481 LogRel(("DnD: Adding URI path '%s' failed with rc=%Rrc\n", pcszPath, rc)); 482 483 return rc; 484 } 485 486 /** 487 * Appends a single path to a transfer list. 488 * 489 * @returns VBox status code. VERR_NOT_SUPPORTED if the path is not supported. 490 * @param pList Transfer list to append to. 491 * @param enmFmt Format of \a pszPaths to append. 492 * @param pcszPath Path to append. Must be part of the list's set root path. 493 * @param fFlags Transfer list flags to use for appending. 494 */ 495 int DnDTransferListAppendPath(PDNDTRANSFERLIST pList, 496 DNDTRANSFERLISTFMT enmFmt, const char *pcszPath, DNDTRANSFERLISTFLAGS fFlags) 497 { 498 AssertPtrReturn(pList, VERR_INVALID_POINTER); 499 AssertPtrReturn(pcszPath, VERR_INVALID_POINTER); 500 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 501 AssertReturn(!(fFlags & DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS), VERR_NOT_SUPPORTED); 502 503 int rc; 504 505 switch (enmFmt) 506 { 507 case DNDTRANSFERLISTFMT_NATIVE: 508 rc = dndTransferListAppendPathNative(pList, pcszPath, fFlags); 509 break; 510 511 case DNDTRANSFERLISTFMT_URI: 512 rc = dndTransferListAppendPathURI(pList, pcszPath, fFlags); 513 break; 514 515 default: 516 AssertFailedStmt(rc = VERR_NOT_SUPPORTED); 517 break; /* Never reached */ 518 } 519 520 return rc; 521 } 522 523 /** 524 * Appends native paths to a transfer list. 525 * 526 * @returns VBox status code. 527 * @param pList Transfer list to append to. 528 * @param enmFmt Format of \a pszPaths to append. 529 * @param pszPaths Buffer of paths to append. 530 * @param cbPaths Size (in bytes) of buffer of paths to append. 531 * @param pcszSeparator Separator string to use. 532 * @param fFlags Transfer list flags to use for appending. 533 */ 534 int DnDTransferListAppendPathsFromBuffer(PDNDTRANSFERLIST pList, 535 DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, 536 const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags) 537 { 538 AssertPtrReturn(pList, VERR_INVALID_POINTER); 539 AssertPtrReturn(pszPaths, VERR_INVALID_POINTER); 540 AssertReturn(cbPaths, VERR_INVALID_PARAMETER); 541 542 char **papszPaths = NULL; 543 size_t cPaths = 0; 544 int rc = RTStrSplit(pszPaths, cbPaths, pcszSeparator, &papszPaths, &cPaths); 545 if (RT_SUCCESS(rc)) 546 rc = DnDTransferListAppendPathsFromArray(pList, enmFmt, papszPaths, cPaths, fFlags); 547 548 for (size_t i = 0; i < cPaths; ++i) 549 RTStrFree(papszPaths[i]); 550 RTMemFree(papszPaths); 551 552 return rc; 553 } 554 555 /** 556 * Appends paths to a transfer list. 557 * 558 * @returns VBox status code. Will return VERR_INVALID_PARAMETER if a common root path could not be found. 559 * @param pList Transfer list to append path to. 560 * @param enmFmt Format of \a papcszPaths to append. 561 * @param papcszPaths Array of paths to append. 562 * @param cPaths Number of paths in \a papcszPaths to append. 563 * @param fFlags Transfer list flags to use for appending. 564 */ 565 int DnDTransferListAppendPathsFromArray(PDNDTRANSFERLIST pList, 566 DNDTRANSFERLISTFMT enmFmt, 567 const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags) 568 { 569 AssertPtrReturn(pList, VERR_INVALID_POINTER); 570 AssertPtrReturn(papcszPaths, VERR_INVALID_POINTER); 571 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 572 573 int rc = VINF_SUCCESS; 574 575 if (!cPaths) /* Nothing to add? Bail out. */ 576 return VINF_SUCCESS; 577 578 /* If we don't have a root path set, try to find the common path of all handed-in paths. */ 579 if (!pList->pszPathRootAbs) 580 { 581 size_t cchRootPath = RTPathFindCommon(papcszPaths, cPaths); 582 if (cchRootPath) 583 { 584 /* Just use the first path in the array as the reference. */ 585 char *pszRootPath = RTStrDupN(papcszPaths[0], cchRootPath); 586 if (pszRootPath) 587 { 588 LogRel2(("DnD: Determined root path is '%s'\n", pszRootPath)); 589 rc = dndTransferListSetRootPath(pList, pszRootPath); 590 RTStrFree(pszRootPath); 97 591 } 98 592 else 99 593 rc = VERR_NO_MEMORY; 100 594 } 101 /* Note: Symlinks already should have been resolved at this point. */ 595 } 596 597 /* 598 * Go through the created list and make sure all entries have the same root path. 599 */ 600 for (size_t i = 0; i < cPaths; i++) 601 { 602 rc = DnDTransferListAppendPath(pList, enmFmt, papcszPaths[i], fFlags); 603 if (RT_FAILURE(rc)) 604 break; 605 } 606 607 LogFlowFuncLeaveRC(rc); 608 return rc; 609 } 610 611 /** 612 * Returns the first transfer object in a list. 613 * 614 * @returns Pointer to transfer object if found, or NULL if not found. 615 * @param pList Transfer list to get first transfer object from. 616 */ 617 PDNDTRANSFEROBJECT DnDTransferListObjGetFirst(PDNDTRANSFERLIST pList) 618 { 619 AssertPtrReturn(pList, NULL); 620 621 return RTListGetFirst(&pList->lstObj, DNDTRANSFEROBJECT, Node); 622 } 623 624 /** 625 * Removes the first DnD transfer object from a transfer list. 626 * 627 * @param pList Transfer list to remove first entry for. 628 */ 629 void DnDTransferListObjRemoveFirst(PDNDTRANSFERLIST pList) 630 { 631 AssertPtrReturnVoid(pList); 632 633 if (!pList->cObj) 634 return; 635 636 PDNDTRANSFEROBJECT pObj = RTListGetFirst(&pList->lstObj, DNDTRANSFEROBJECT, Node); 637 AssertPtr(pObj); 638 639 uint64_t cbSize = DnDTransferObjectGetSize(pObj); 640 Assert(pList->cbObjTotal >= cbSize); 641 pList->cbObjTotal -= cbSize; /* Adjust total size. */ 642 643 dndTransferListObjFree(pList, pObj); 644 } 645 646 /** 647 * Returns all root entries of a transfer list as a string. 648 * 649 * @returns VBox status code. 650 * @param pList Transfer list to return root paths for. 651 * @param pcszPathBase Root path to use as a base path. If NULL, the list's absolute root path will be used (if any). 652 * @param pcszSeparator Separator to use for separating the root entries. 653 * @param ppszBuffer Where to return the allocated string on success. Needs to be free'd with RTStrFree(). 654 * @param pcbBuffer Where to return the size (in bytes) of the allocated string on success, including terminator. 655 */ 656 int DnDTransferListGetRootsEx(PDNDTRANSFERLIST pList, 657 DNDTRANSFERLISTFMT enmFmt, const char *pcszPathBase, const char *pcszSeparator, 658 char **ppszBuffer, size_t *pcbBuffer) 659 { 660 AssertPtrReturn(pList, VERR_INVALID_POINTER); 661 /* pcszPathBase can be NULL. */ 662 AssertPtrReturn(pcszSeparator, VERR_INVALID_POINTER); 663 AssertPtrReturn(ppszBuffer, VERR_INVALID_POINTER); 664 AssertPtrReturn(pcbBuffer, VERR_INVALID_POINTER); 665 666 char *pszString = NULL; 667 668 /* Find out which root path to use. */ 669 const char *pcszPathRootTmp = pcszPathBase ? pcszPathBase : pList->pszPathRootAbs; 670 /* pcszPathRootTmp can be NULL*/ 671 672 LogFlowFunc(("Using root path '%s'\n", pcszPathRootTmp ? pcszPathRootTmp : "<None>")); 673 674 int rc = DnDPathValidate(pcszPathRootTmp, false /* fMustExist */); 675 if (RT_FAILURE(rc)) 676 return rc; 677 678 char szPath[RTPATH_MAX]; 679 680 PDNDTRANSFERLISTROOT pRoot; 681 RTListForEach(&pList->lstRoot, pRoot, DNDTRANSFERLISTROOT, Node) 682 { 683 if (pcszPathRootTmp) 684 { 685 rc = RTStrCopy(szPath, sizeof(szPath), pcszPathRootTmp); 686 AssertRCBreak(rc); 687 } 688 689 rc = RTPathAppend(szPath, sizeof(szPath), pRoot->pszPathRoot); 690 AssertRCBreak(rc); 691 692 if (enmFmt == DNDTRANSFERLISTFMT_URI) 693 { 694 char *pszPathURI = RTUriFileCreate(szPath); 695 AssertPtrBreakStmt(pszPathURI, rc = VERR_NO_MEMORY); 696 697 rc = RTStrAAppend(&pszString, pszPathURI); 698 RTStrFree(pszPathURI); 699 AssertRCBreak(rc); 700 } 102 701 else 103 rc = VERR_NOT_SUPPORTED; 104 } 105 106 LogFlowFuncLeaveRC(rc); 107 return rc; 108 } 109 110 int DnDURIList::appendPathRecursive(const char *pcszSrcPath, 111 const char *pcszDstPath, const char *pcszDstBase, size_t cchDstBase, 112 DNDURILISTFLAGS fFlags) 113 { 114 AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER); 115 AssertPtrReturn(pcszDstBase, VERR_INVALID_POINTER); 116 AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER); 117 118 LogFlowFunc(("pcszSrcPath=%s, pcszDstPath=%s, pcszDstBase=%s, cchDstBase=%zu, fFlags=0x%x\n", 119 pcszSrcPath, pcszDstPath, pcszDstBase, cchDstBase, fFlags)); 120 121 RTFSOBJINFO objInfo; 122 int rc = RTPathQueryInfo(pcszSrcPath, &objInfo, RTFSOBJATTRADD_NOTHING); 702 { 703 rc = RTStrAAppend(&pszString, szPath); 704 AssertRCBreak(rc); 705 } 706 707 rc = RTStrAAppend(&pszString, pcszSeparator); 708 AssertRCBreak(rc); 709 } 710 123 711 if (RT_SUCCESS(rc)) 124 712 { 125 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 126 { 127 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); 713 *ppszBuffer = pszString; 714 *pcbBuffer = pszString ? strlen(pszString) + 1 /* Include termination */ : 0; 715 } 716 else 717 RTStrFree(pszString); 718 return rc; 719 } 720 721 int DnDTransferListGetRoots(PDNDTRANSFERLIST pList, 722 DNDTRANSFERLISTFMT enmFmt, char **ppszBuffer, size_t *pcbBuffer) 723 { 724 return DnDTransferListGetRootsEx(pList, enmFmt, "" /* pcszPathRoot */, DND_PATH_SEPARATOR, 725 ppszBuffer, pcbBuffer); 726 } 727 728 /** 729 * Returns the total root entries count for a DnD transfer list. 730 * 731 * @returns Total number of root entries. 732 * @param pList Transfer list to return total number of root entries for. 733 */ 734 uint64_t DnDTransferListGetRootCount(PDNDTRANSFERLIST pList) 735 { 736 AssertPtrReturn(pList, 0); 737 return pList->cRoots; 738 } 739 740 /** 741 * Returns the absolute root path for a DnD transfer list. 742 * 743 * @returns Pointer to the root path. 744 * @param pList Transfer list to return root path for. 745 */ 746 const char *DnDTransferListGetRootPathAbs(PDNDTRANSFERLIST pList) 747 { 748 AssertPtrReturn(pList, NULL); 749 return pList->pszPathRootAbs; 750 } 751 752 /** 753 * Returns the total transfer object count for a DnD transfer list. 754 * 755 * @returns Total number of transfer objects. 756 * @param pList Transfer list to return total number of transfer objects for. 757 */ 758 uint64_t DnDTransferListObjCount(PDNDTRANSFERLIST pList) 759 { 760 AssertPtrReturn(pList, 0); 761 return pList->cObj; 762 } 763 764 /** 765 * Returns the total bytes of all handled transfer objects for a DnD transfer list. 766 * 767 * @returns VBox status code. 768 * @param pList Transfer list to return total bytes for. 769 */ 770 uint64_t DnDTransferListObjTotalBytes(PDNDTRANSFERLIST pList) 771 { 772 AssertPtrReturn(pList, 0); 773 return pList->cbObjTotal; 774 } 775 776 /** 777 * Sets the absolute root path of a transfer list. 778 * 779 * @returns VBox status code. 780 * @param pList Transfer list to set root path for. 781 * @param pcszRootPathAbs Absolute root path to set. 782 */ 783 static int dndTransferListSetRootPath(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs) 784 { 785 AssertPtrReturn(pList, VERR_INVALID_POINTER); 786 AssertPtrReturn(pcszRootPathAbs, VERR_INVALID_POINTER); 787 AssertReturn(pList->pszPathRootAbs == NULL, VERR_WRONG_ORDER); /* Already initialized? */ 788 789 LogFlowFunc(("pcszRootPathAbs=%s\n", pcszRootPathAbs)); 790 791 char szRootPath[RTPATH_MAX]; 792 int rc = RTStrCopy(szRootPath, sizeof(szRootPath), pcszRootPathAbs); 793 if (RT_FAILURE(rc)) 794 return rc; 795 796 /* Note: The list's root path is kept in native style, so no conversion needed here. */ 797 798 RTPathEnsureTrailingSeparatorEx(szRootPath, sizeof(szRootPath), RTPATH_STR_F_STYLE_HOST); 799 800 pList->pszPathRootAbs = RTStrDup(szRootPath); 801 if (pList->pszPathRootAbs) 802 { 803 LogFlowFunc(("Root path is '%s'\n", pList->pszPathRootAbs)); 804 } 805 else 806 rc = VERR_NO_MEMORY; 807 808 return rc; 809 } 810 811 static int dndTransferListRootAdd(PDNDTRANSFERLIST pList, const char *pcszRoot) 812 { 813 int rc; 814 815 PDNDTRANSFERLISTROOT pRoot = (PDNDTRANSFERLISTROOT)RTMemAllocZ(sizeof(DNDTRANSFERLISTROOT)); 816 if (pRoot) 817 { 818 pRoot->pszPathRoot = RTStrDup(pcszRoot); 819 if (pRoot->pszPathRoot) 820 { 821 RTListAppend(&pList->lstRoot, &pRoot->Node); 822 pList->cRoots++; 823 824 rc = VINF_SUCCESS; 825 } 826 else 827 rc = VERR_NO_MEMORY; 828 829 if (RT_FAILURE(rc)) 830 { 831 RTMemFree(pRoot); 832 pRoot = NULL; 833 } 834 } 835 else 836 rc = VERR_NO_MEMORY; 837 838 return rc; 839 } 840 841 /** 842 * Frees an internal DnD transfer root. 843 * 844 * @param pList Transfer list to free root for. 845 * @param pRootObj Transfer list root to free. The pointer will be invalid after calling. 846 */ 847 static void dndTransferListRootFree(PDNDTRANSFERLIST pList, PDNDTRANSFERLISTROOT pRootObj) 848 { 849 if (!pRootObj) 850 return; 851 852 RTStrFree(pRootObj->pszPathRoot); 853 854 RTListNodeRemove(&pRootObj->Node); 855 RTMemFree(pRootObj); 856 857 AssertReturnVoid(pList->cRoots); 858 pList->cRoots--; 859 } 860 861 862 #if 0 863 /** 864 * Appends a single URI path to a transfer list. 865 * 866 * @returns VBox status code. 867 * @param pList Transfer list to append URI path to. 868 * @param pszURIPath URI path to append. 869 * @param fFlags Transfer list flags to use for appending. 870 */ 871 int DnDTransferListURIAppendPath(PDNDTRANSFERLIST pList, const char *pszURIPath, DNDTRANSFERLISTFLAGS fFlags) 872 { 873 AssertPtrReturn(pList, VERR_INVALID_POINTER); 874 AssertPtrReturn(pszURIPath, VERR_INVALID_POINTER); 875 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 876 877 in rc; 878 879 /* Query the path component of a file URI. If this hasn't a 880 * file scheme, NULL is returned. */ 881 char *pszFilePath = RTUriFilePathEx(pszURIPath, RTPATH_STR_F_STYLE_UNIX, &pszFilePath, 0 /*cbPath*/, NULL /*pcchPath*/); 882 LogFlowFunc(("pszPath=%s, pszFilePath=%s\n", pszFilePath)); 883 if (pszFilePath) 884 { 885 rc = DnDPathValidate(pszFilePath, false /* fMustExist */); 886 if (RT_SUCCESS(rc)) 887 { 888 uint32_t fPathConvert = DNDPATHCONVERT_FLAGS_TRANSPORT; 889 #ifdef RT_OS_WINDOWS 890 fPathConvert |= DNDPATHCONVERT_FLAGS_TO_DOS; 891 #endif 892 rc = DnDPathConvert(pszFilePath, strlen(pszFilePath) + 1, fPathConvert); 128 893 if (RT_SUCCESS(rc)) 129 894 { 130 RTDIR hDir; 131 rc = RTDirOpen(&hDir, pcszSrcPath); 132 if (RT_SUCCESS(rc)) 895 LogRel2(("DnD: Got URI data item '%s'\n", pszFilePath)); 896 897 PDNDTRANSFERLISTROOT pRoot = (PDNDTRANSFERLISTROOT)RTMemAlloc(sizeof(DNDTRANSFERLISTROOT)); 898 if (pRoot) 133 899 { 134 size_t cbDirEntry = 0; 135 PRTDIRENTRYEX pDirEntry = NULL; 136 do 137 { 138 /* Retrieve the next directory entry. */ 139 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); 140 if (RT_FAILURE(rc)) 141 { 142 if (rc == VERR_NO_MORE_FILES) 143 rc = VINF_SUCCESS; 144 break; 145 } 146 147 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK) 148 { 149 case RTFS_TYPE_DIRECTORY: 150 { 151 /* Skip "." and ".." entries. */ 152 if (RTDirEntryExIsStdDotLink(pDirEntry)) 153 break; 154 155 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName); 156 if (pszSrc) 157 { 158 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName); 159 if (pszDst) 160 { 161 rc = appendPathRecursive(pszSrc, pszDst, pcszDstBase, cchDstBase, fFlags); 162 RTStrFree(pszDst); 163 } 164 else 165 rc = VERR_NO_MEMORY; 166 167 RTStrFree(pszSrc); 168 } 169 else 170 rc = VERR_NO_MEMORY; 171 break; 172 } 173 174 case RTFS_TYPE_FILE: 175 { 176 char *pszSrc = RTPathJoinA(pcszSrcPath, pDirEntry->szName); 177 if (pszSrc) 178 { 179 char *pszDst = RTPathJoinA(pcszDstPath, pDirEntry->szName); 180 if (pszDst) 181 { 182 rc = addEntry(pszSrc, &pszDst[cchDstBase], fFlags); 183 RTStrFree(pszDst); 184 } 185 else 186 rc = VERR_NO_MEMORY; 187 RTStrFree(pszSrc); 188 } 189 else 190 rc = VERR_NO_MEMORY; 191 break; 192 } 193 case RTFS_TYPE_SYMLINK: 194 { 195 if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) 196 { 197 char *pszSrc = RTPathRealDup(pcszDstBase); 198 if (pszSrc) 199 { 200 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); 201 if (RT_SUCCESS(rc)) 202 { 203 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 204 { 205 LogFlowFunc(("Directory entry is symlink to directory\n")); 206 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); 207 } 208 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 209 { 210 LogFlowFunc(("Directory entry is symlink to file\n")); 211 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); 212 } 213 else 214 rc = VERR_NOT_SUPPORTED; 215 } 216 217 RTStrFree(pszSrc); 218 } 219 else 220 rc = VERR_NO_MEMORY; 221 } 222 break; 223 } 224 225 default: 226 break; 227 } 228 229 } while (RT_SUCCESS(rc)); 230 231 RTDirReadExAFree(&pDirEntry, &cbDirEntry); 232 RTDirClose(hDir); 233 } 234 } 235 } 236 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 237 { 238 rc = addEntry(pcszSrcPath, &pcszDstPath[cchDstBase], fFlags); 239 } 240 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode)) 241 { 242 if (fFlags & DNDURILIST_FLAGS_RESOLVE_SYMLINKS) 243 { 244 char *pszSrc = RTPathRealDup(pcszSrcPath); 245 if (pszSrc) 246 { 247 rc = RTPathQueryInfo(pszSrc, &objInfo, RTFSOBJATTRADD_NOTHING); 248 if (RT_SUCCESS(rc)) 249 { 250 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode)) 251 { 252 LogFlowFunc(("Symlink to directory\n")); 253 rc = appendPathRecursive(pszSrc, pcszDstPath, pcszDstBase, cchDstBase, fFlags); 254 } 255 else if (RTFS_IS_FILE(objInfo.Attr.fMode)) 256 { 257 LogFlowFunc(("Symlink to file\n")); 258 rc = addEntry(pszSrc, &pcszDstPath[cchDstBase], fFlags); 259 } 260 else 261 rc = VERR_NOT_SUPPORTED; 262 } 263 264 RTStrFree(pszSrc); 900 pRoot->pszPathRoot = pszFilePath; 901 902 RTListAppend(&pList->lstRoot, &pRoot->Node); 903 pList->cRoots++; 904 265 905 } 266 906 else 267 907 rc = VERR_NO_MEMORY; 268 908 } 909 else 910 LogRel(("DnD: Path conversion of URI data item '%s' failed with %Rrc\n", pszFilePath, rc)); 269 911 } 270 912 else 271 rc = VERR_NOT_SUPPORTED; 913 LogRel(("DnD: Path validation for URI data item '%s' failed with %Rrc\n", pszFilePath, rc)); 914 915 if (RT_FAILURE(rc)) 916 RTStrFree(pszFilePath); 272 917 } 273 918 … … 276 921 } 277 922 278 int DnDURIList::AppendNativePath(const char *pszPath, DNDURILISTFLAGS fFlags) 279 { 280 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); 281 282 int rc; 283 char *pszPathNative = RTStrDup(pszPath); 284 if (pszPathNative) 285 { 286 RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */); 287 288 char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */, 289 pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */); 290 if (pszPathURI) 291 { 292 rc = AppendURIPath(pszPathURI, fFlags); 293 RTStrFree(pszPathURI); 294 } 295 else 296 rc = VERR_INVALID_PARAMETER; 297 298 RTStrFree(pszPathNative); 299 } 300 else 301 rc = VERR_NO_MEMORY; 302 303 return rc; 304 } 305 306 int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths, 307 DNDURILISTFLAGS fFlags) 308 { 309 AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER); 310 AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER); 311 312 RTCList<RTCString> lstPaths 313 = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n"); 314 return AppendNativePathsFromList(lstPaths, fFlags); 315 } 316 317 int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths, 318 DNDURILISTFLAGS fFlags) 319 { 320 int rc = VINF_SUCCESS; 321 322 for (size_t i = 0; i < lstNativePaths.size(); i++) 323 { 324 const RTCString &strPath = lstNativePaths.at(i); 325 rc = AppendNativePath(strPath.c_str(), fFlags); 326 if (RT_FAILURE(rc)) 327 break; 328 } 329 330 LogFlowFuncLeaveRC(rc); 331 return rc; 332 } 333 334 int DnDURIList::AppendURIPath(const char *pszURI, DNDURILISTFLAGS fFlags) 335 { 336 AssertPtrReturn(pszURI, VERR_INVALID_POINTER); 337 AssertReturn(!(fFlags & ~DNDURILIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 338 /** @todo Check for string termination? */ 339 340 RTURIPARSED Parsed; 341 int rc = RTUriParse(pszURI, &Parsed); 342 if (RT_FAILURE(rc)) 343 return rc; 344 345 char *pszSrcPath = NULL; 346 347 /* file://host.example.com/path/to/file.txt */ 348 const char *pszParsedAuthority = RTUriParsedAuthority(pszURI, &Parsed); 349 if ( pszParsedAuthority 350 && pszParsedAuthority[0] != '\0') /* Authority present? */ 351 { 352 const char *pszParsedPath = RTUriParsedPath(pszURI, &Parsed); 353 if (pszParsedPath) 354 { 355 /* Always use UNIXy paths internally. */ 356 if (RTStrAPrintf(&pszSrcPath, "//%s%s", pszParsedAuthority, pszParsedPath) == -1) 357 rc = VERR_NO_MEMORY; 358 } 359 else 360 rc = VERR_INVALID_PARAMETER; 361 } 362 else 363 { 364 pszSrcPath = RTUriFilePath(pszURI); 365 if (!pszSrcPath) 366 rc = VERR_INVALID_PARAMETER; 367 } 368 369 LogFlowFunc(("pszURI=%s, fFlags=0x%x -> pszParsedAuthority=%s, pszSrcPath=%s, rc=%Rrc\n", 370 pszURI, fFlags, pszParsedAuthority ? pszParsedAuthority : "<None>", pszSrcPath, rc)); 371 372 if (RT_SUCCESS(rc)) 373 { 374 /* Add the path to our internal file list (recursive in 375 * the case of a directory). */ 376 size_t cbPathLen = RTPathStripTrailingSlash(pszSrcPath); 377 if (cbPathLen) 378 { 379 char *pszFileName = RTPathFilename(pszSrcPath); 380 if (pszFileName) 381 { 382 Assert(pszFileName >= pszSrcPath); 383 size_t cchDstBase = (fFlags & DNDURILIST_FLAGS_ABSOLUTE_PATHS) 384 ? 0 /* Use start of path as root. */ 385 : pszFileName - pszSrcPath; 386 char *pszDstPath = &pszSrcPath[cchDstBase]; 387 rc = DnDPathConvert(pszDstPath, strlen(pszDstPath), DNDPATHCONVERT_FLAGS_NONE); 388 if (RT_SUCCESS(rc)) 389 { 390 m_lstRoot.append(pszDstPath); 391 392 LogFlowFunc(("pszSrcPath=%s, pszFileName=%s, pszDstPath=%s\n", 393 pszSrcPath, pszFileName, pszDstPath)); 394 395 rc = appendPathRecursive(pszSrcPath, pszSrcPath, pszSrcPath, cchDstBase, fFlags); 396 } 397 } 398 else 399 rc = VERR_PATH_NOT_FOUND; 400 } 401 else 402 rc = VERR_INVALID_PARAMETER; 403 } 404 405 RTStrFree(pszSrcPath); 406 407 LogFlowFuncLeaveRC(rc); 408 return rc; 409 } 410 411 int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths, 412 DNDURILISTFLAGS fFlags) 413 { 923 /** 924 * Appends transfer list items from an URI string buffer. 925 * 926 * @returns VBox status code. 927 * @param pList Transfer list to append list data to. 928 * @param pszURIPaths String list to append. 929 * @param cbURIPaths Size (in bytes) of string list to append. 930 * @param pcszSeparator Separator string to use for separating strings of \a pszURIPathsAbs. 931 * @param fFlags Transfer list flags to use for appending. 932 */ 933 int DnDTransferListURIAppendFromBuffer(PDNDTRANSFERLIST pList, 934 const char *pszURIPaths, size_t cbURIPaths, 935 const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags) 936 { 937 AssertPtrReturn(pList, VERR_INVALID_POINTER); 414 938 AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER); 415 939 AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER); 416 417 RTCList<RTCString> lstPaths 418 = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n"); 419 return AppendURIPathsFromList(lstPaths, fFlags); 420 } 421 422 int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI, 423 DNDURILISTFLAGS fFlags) 424 { 425 int rc = VINF_SUCCESS; 426 427 for (size_t i = 0; i < lstURI.size(); i++) 428 { 429 RTCString strURI = lstURI.at(i); 430 rc = AppendURIPath(strURI.c_str(), fFlags); 431 432 if (RT_FAILURE(rc)) 433 break; 940 AssertReturn(!(fFlags & ~DNDTRANSFERLIST_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 941 942 char **papszPaths = NULL; 943 size_t cPaths = 0; 944 int rc = RTStrSplit(pszURIPaths, cbURIPaths, pcszSeparator, &papszPaths, &cPaths); 945 if (RT_SUCCESS(rc)) 946 { 947 for (size_t i = 0; i < cPaths; i++) 948 { 949 rc = DnDTransferListURIAppendPath(pList, papszPaths[i], fFlags); 950 if (RT_FAILURE(rc)) 951 break; 952 } 953 954 for (size_t i = 0; i < cPaths; ++i) 955 RTStrFree(papszPaths[i]); 956 RTMemFree(papszPaths); 434 957 } 435 958 … … 437 960 return rc; 438 961 } 439 440 void DnDURIList::Clear(void)441 {442 m_lstRoot.clear();443 444 for (size_t i = 0; i < m_lstTree.size(); i++)445 {446 DnDURIObject *pCurObj = m_lstTree.at(i);447 AssertPtr(pCurObj);448 delete pCurObj;449 }450 m_lstTree.clear();451 452 m_cTotal = 0;453 m_cbTotal = 0;454 }455 456 void DnDURIList::RemoveFirst(void)457 {458 if (m_lstTree.isEmpty())459 return;460 461 DnDURIObject *pCurObj = m_lstTree.first();462 AssertPtr(pCurObj);463 464 uint64_t cbSize = pCurObj->GetSize();465 Assert(m_cbTotal >= cbSize);466 m_cbTotal -= cbSize; /* Adjust total size. */467 468 pCurObj->Close();469 delete pCurObj;470 471 m_lstTree.removeFirst();472 }473 474 int DnDURIList::SetFromURIData(const void *pvData, size_t cbData, DNDURILISTFLAGS fFlags)475 {476 Assert(fFlags == 0); RT_NOREF1(fFlags);477 AssertPtrReturn(pvData, VERR_INVALID_POINTER);478 AssertReturn(cbData, VERR_INVALID_PARAMETER);479 480 if (!RTStrIsValidEncoding(static_cast<const char *>(pvData)))481 return VERR_INVALID_PARAMETER;482 483 RTCList<RTCString> lstURI =484 RTCString(static_cast<const char *>(pvData), cbData - 1).split("\r\n");485 if (lstURI.isEmpty())486 return VINF_SUCCESS;487 488 int rc = VINF_SUCCESS;489 490 for (size_t i = 0; i < lstURI.size(); ++i)491 {492 /* Query the path component of a file URI. If this hasn't a493 * file scheme, NULL is returned. */494 const char *pszURI = lstURI.at(i).c_str();495 char *pszFilePath = RTUriFilePath(pszURI);496 #ifdef DEBUG_andy497 LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));498 962 #endif 499 if (pszFilePath)500 {501 rc = DnDPathConvert(pszFilePath, strlen(pszFilePath), DNDPATHCONVERT_FLAGS_NONE);502 if (RT_SUCCESS(rc))503 {504 m_lstRoot.append(pszFilePath);505 m_cTotal++;506 }507 508 RTStrFree(pszFilePath);509 }510 else511 rc = VERR_INVALID_PARAMETER;512 513 if (RT_FAILURE(rc))514 break;515 }516 517 return rc;518 }519 520 RTCString DnDURIList::GetRootEntries(const RTCString &strPathBase /* = "" */,521 const RTCString &strSeparator /* = "\r\n" */) const522 {523 RTCString strRet;524 for (size_t i = 0; i < m_lstRoot.size(); i++)525 {526 const char *pszCurRoot = m_lstRoot.at(i).c_str();527 #ifdef DEBUG_andy528 LogFlowFunc(("pszCurRoot=%s\n", pszCurRoot));529 #endif530 if (strPathBase.isNotEmpty())531 {532 char *pszPath = RTPathJoinA(strPathBase.c_str(), pszCurRoot);533 if (pszPath)534 {535 char *pszPathURI = RTUriFileCreate(pszPath);536 if (pszPathURI)537 {538 strRet += RTCString(pszPathURI) + strSeparator;539 LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));540 RTStrFree(pszPathURI);541 }542 543 RTStrFree(pszPath);544 545 if (!pszPathURI)546 break;547 }548 else549 break;550 }551 else552 {553 char *pszPathURI = RTUriFileCreate(pszCurRoot);554 if (pszPathURI)555 {556 strRet += RTCString(pszPathURI) + strSeparator;557 LogFlowFunc(("URI: %s\n", strRet.c_str()));558 RTStrFree(pszPathURI);559 }560 else561 break;562 }563 }564 565 return strRet;566 }567 -
trunk/src/VBox/GuestHost/DragAndDrop/DnDTransferObject.cpp
r85369 r85371 1 1 /* $Id$ */ 2 2 /** @file 3 * DnD - URI object class. For handling creation/reading/writing to files and directories on host or guest side.3 * DnD - Transfer object implemenation for handling creation/reading/writing to files and directories on host or guest side. 4 4 */ 5 5 … … 28 28 #include <iprt/fs.h> 29 29 #include <iprt/path.h> 30 #include <iprt/string.h> 30 31 #include <iprt/uri.h> 31 32 32 33 #include <VBox/log.h> 33 34 34 35 DnDURIObject::DnDURIObject(Type enmType /* = Type_Unknown */, const RTCString &strPathAbs /* = "" */) 36 : m_enmType(Type_Unknown) 37 { 38 if ( enmType != Type_Unknown 39 && strPathAbs.isNotEmpty()) 40 { 41 int rc2 = Init(enmType, strPathAbs); 42 AssertRC(rc2); 43 } 44 } 45 46 DnDURIObject::~DnDURIObject(void) 47 { 48 closeInternal(); 35 /********************************************************************************************************************************* 36 * Prototypes * 37 *********************************************************************************************************************************/ 38 static void dndTransferObjectCloseInternal(PDNDTRANSFEROBJECT pObj); 39 static int dndTransferObjectQueryInfoInternal(PDNDTRANSFEROBJECT pObj); 40 41 42 /** 43 * Initializes the object with an expected object type and file path. 44 * 45 * @returns VBox status code. 46 * @param pObj DnD transfer object to initialize. 47 * @param enmType Type we expect this object to be. 48 * @param pcszPathSrcAbs Absolute source (local) path of file this object represents. Can be empty (e.g. for root stuff). 49 * @param pcszPathDst Relative path of file this object represents at the destination. 50 * Together with \a pcszPathSrcAbs this represents the complete absolute local path. 51 */ 52 int DnDTransferObjectInit(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJTYPE enmType, const char *pcszPathSrcAbs, const char *pcszPathDst) 53 { 54 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 55 AssertReturn(pObj->enmType == DNDTRANSFEROBJTYPE_UNKNOWN, VERR_WRONG_ORDER); /* Already initialized? */ 56 /* pcszPathSrcAbs can be empty. */ 57 AssertPtrReturn(pcszPathDst, VERR_INVALID_POINTER); 58 59 switch (enmType) 60 { 61 case DNDTRANSFEROBJTYPE_FILE: 62 { 63 pObj->u.File.hFile = NIL_RTFILE; 64 break; 65 } 66 67 case DNDTRANSFEROBJTYPE_DIRECTORY: 68 { 69 pObj->u.Dir.hDir = NIL_RTDIR; 70 break; 71 } 72 73 default: 74 AssertFailedReturn(VERR_NOT_IMPLEMENTED); 75 break; /* Never reached */ 76 } 77 78 int rc = DnDPathValidate(pcszPathDst, false /* Does not need to exist */); 79 if (RT_FAILURE(rc)) 80 return rc; 81 82 char szPath[RTPATH_MAX + 1]; 83 84 /* Save the index (in characters) where the first destination segment starts. */ 85 if ( pcszPathSrcAbs 86 && RTStrNLen(pcszPathSrcAbs, RTSTR_MAX)) 87 { 88 rc = DnDPathValidate(pcszPathSrcAbs, false /* Does not need to exist */); 89 if (RT_FAILURE(rc)) 90 return rc; 91 92 rc = RTStrCopy(szPath, sizeof(szPath), pcszPathSrcAbs); 93 if (RT_SUCCESS(rc)) 94 rc = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath)) == 0 ? VERR_BUFFER_OVERFLOW : VINF_SUCCESS; 95 96 /* Save the index (in characters) where the destination part starts. */ 97 pObj->idxDst = (uint16_t)RTStrNLen(szPath, RTSTR_MAX); 98 AssertReturn(pObj->idxDst != RTSTR_MAX, VERR_INVALID_PARAMETER); 99 } 100 else 101 { 102 szPath[0] = '\0'; /* Init empty string. */ 103 pObj->idxDst = 0; 104 } 105 106 if (RT_FAILURE(rc)) 107 return rc; 108 109 /* Append the destination part. */ 110 rc = RTPathAppend(szPath, sizeof(szPath), pcszPathDst); 111 if ( RT_SUCCESS(rc) 112 && enmType == DNDTRANSFEROBJTYPE_DIRECTORY) 113 rc = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath)) == 0 ? VERR_BUFFER_OVERFLOW : VINF_SUCCESS; 114 115 if (RT_FAILURE(rc)) 116 return rc; 117 118 pObj->pszPath = RTStrDup(szPath); 119 if (!pObj->pszPath) 120 return VERR_NO_MEMORY; 121 122 /* Convert paths into transport format. */ 123 rc = DnDPathConvert(pObj->pszPath, strlen(pObj->pszPath), DNDPATHCONVERT_FLAGS_TRANSPORT); 124 if (RT_FAILURE(rc)) 125 { 126 RTStrFree(pObj->pszPath); 127 pObj->pszPath = NULL; 128 return rc; 129 } 130 131 LogFlowFunc(("enmType=%RU32, pcszPathSrcAbs=%s, pcszPathDst=%s -> pszPath=%s\n", 132 enmType, pcszPathSrcAbs, pcszPathDst, pObj->pszPath)); 133 134 pObj->enmType = enmType; 135 136 return VINF_SUCCESS; 137 } 138 139 /** 140 * Destroys a DnD transfer object. 141 * 142 * @param pObj DnD transfer object to destroy. 143 */ 144 void DnDTransferObjectDestroy(PDNDTRANSFEROBJECT pObj) 145 { 146 if (!pObj) 147 return; 148 149 DnDTransferObjectReset(pObj); 49 150 } 50 151 51 152 /** 52 153 * Closes the object's internal handles (to files / ...). 53 */ 54 void DnDURIObject::closeInternal(void) 55 { 56 LogFlowThisFuncEnter(); 154 * 155 * @param pObj DnD transfer object to close internally. 156 */ 157 static void dndTransferObjectCloseInternal(PDNDTRANSFEROBJECT pObj) 158 { 159 AssertPtrReturnVoid(pObj); 57 160 58 161 int rc; 59 162 60 switch (m_enmType) 61 { 62 case Type_File: 63 { 64 if (RTFileIsValid(u.File.hFile)) 163 LogRel2(("DnD: Closing '%s'\n", pObj->pszPath)); 164 165 switch (pObj->enmType) 166 { 167 case DNDTRANSFEROBJTYPE_FILE: 168 { 169 if (RTFileIsValid(pObj->u.File.hFile)) 65 170 { 66 LogRel2(("DnD: Closing file '%s'\n", m_strPathAbs.c_str())); 67 68 rc = RTFileClose(u.File.hFile); 171 rc = RTFileClose(pObj->u.File.hFile); 69 172 if (RT_SUCCESS(rc)) 70 173 { 71 u.File.hFile = NIL_RTFILE;72 RT_ZERO( u.File.objInfo);174 pObj->u.File.hFile = NIL_RTFILE; 175 RT_ZERO(pObj->u.File.objInfo); 73 176 } 74 177 else 75 LogRel(("DnD: Closing file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));178 LogRel(("DnD: Closing file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 76 179 } 77 180 break; 78 181 } 79 182 80 case Type_Directory:81 { 82 if (RTDirIsValid( u.Dir.hDir))183 case DNDTRANSFEROBJTYPE_DIRECTORY: 184 { 185 if (RTDirIsValid(pObj->u.Dir.hDir)) 83 186 { 84 LogRel2(("DnD: Closing directory '%s'\n", m_strPathAbs.c_str())); 85 86 rc = RTDirClose(u.Dir.hDir); 187 rc = RTDirClose(pObj->u.Dir.hDir); 87 188 if (RT_SUCCESS(rc)) 88 189 { 89 u.Dir.hDir = NIL_RTDIR;90 RT_ZERO( u.Dir.objInfo);190 pObj->u.Dir.hDir = NIL_RTDIR; 191 RT_ZERO(pObj->u.Dir.objInfo); 91 192 } 92 193 else 93 LogRel(("DnD: Closing directory '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));194 LogRel(("DnD: Closing directory '%s' failed with %Rrc\n", pObj->pszPath, rc)); 94 195 } 95 196 break; … … 106 207 * Closes the object. 107 208 * This also closes the internal handles associated with the object (to files / ...). 108 */ 109 void DnDURIObject::Close(void) 110 { 111 closeInternal(); 209 * 210 * @param pObj DnD transfer object to close. 211 */ 212 void DnDTransferObjectClose(PDNDTRANSFEROBJECT pObj) 213 { 214 AssertPtrReturnVoid(pObj); 215 216 dndTransferObjectCloseInternal(pObj); 217 } 218 219 /** 220 * Returns the absolute source path of the object. 221 * 222 * @return Absolute source path of the object. 223 * @param pObj DnD transfer object to get source path for. 224 */ 225 const char *DnDTransferObjectGetSourcePath(PDNDTRANSFEROBJECT pObj) 226 { 227 AssertPtrReturn(pObj, NULL); 228 return pObj->pszPath; 229 } 230 231 /** 232 * Returns the (relative) destination path of the object, in transport style. 233 * 234 * @return Relative destination path of the object, or NULL if not set. 235 * @param pObj DnD transfer object to get destination path for. 236 */ 237 const char *DnDTransferObjectGetDestPath(PDNDTRANSFEROBJECT pObj) 238 { 239 AssertPtrReturn(pObj, NULL); 240 241 if (!pObj->pszPath) 242 return NULL; 243 244 AssertReturn(strlen(pObj->pszPath) >= pObj->idxDst, NULL); 245 246 return &pObj->pszPath[pObj->idxDst]; 247 } 248 249 /** 250 * Returns the (relative) destination path of the object, extended version. 251 * 252 * @return VBox status code, or VERR_NOT_FOUND if not initialized yet. 253 * @param pObj DnD transfer object to get destination path for. 254 * @param enmStyle Which path style to return. 255 * @param pszBuf Where to store the path. 256 * @param cbBuf Size (in bytes) where to store the path. 257 */ 258 int DnDTransferObjectGetDestPathEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJPATHSTYLE enmStyle, char *pszBuf, size_t cbBuf) 259 { 260 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 261 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER); 262 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 263 264 if (!pObj->pszPath) 265 return VERR_NOT_FOUND; 266 267 AssertReturn(strlen(pObj->pszPath) >= pObj->idxDst, VERR_INTERNAL_ERROR); 268 269 int rc = RTStrCopy(pszBuf, cbBuf, &pObj->pszPath[pObj->idxDst]); 270 if ( RT_SUCCESS(rc) 271 && enmStyle == DNDTRANSFEROBJPATHSTYLE_DOS) 272 rc = DnDPathConvert(pszBuf, cbBuf, DNDPATHCONVERT_FLAGS_TO_DOS); 273 274 return rc; 112 275 } 113 276 … … 116 279 * 117 280 * @return File / directory mode. 118 */ 119 RTFMODE DnDURIObject::GetMode(void) const 120 { 121 switch (m_enmType) 122 { 123 case Type_File: 124 return u.File.objInfo.Attr.fMode; 125 126 case Type_Directory: 127 return u.Dir.objInfo.Attr.fMode; 128 129 default: 130 break; 131 } 132 133 AssertFailed(); 281 * @param pObj DnD transfer object to get directory / file mode for. 282 */ 283 RTFMODE DnDTransferObjectGetMode(PDNDTRANSFEROBJECT pObj) 284 { 285 AssertPtrReturn(pObj, 0); 286 287 switch (pObj->enmType) 288 { 289 case DNDTRANSFEROBJTYPE_FILE: 290 return pObj->u.File.objInfo.Attr.fMode; 291 292 case DNDTRANSFEROBJTYPE_DIRECTORY: 293 return pObj->u.Dir.objInfo.Attr.fMode; 294 295 default: 296 break; 297 } 298 134 299 return 0; 135 300 } … … 138 303 * Returns the bytes already processed (read / written). 139 304 * 140 * Note: Only applies if the object is of type DnD URIObject::Type_File.305 * Note: Only applies if the object is of type DnDTransferObjectType_File. 141 306 * 142 307 * @return Bytes already processed (read / written). 143 */ 144 uint64_t DnDURIObject::GetProcessed(void) const 145 { 146 if (m_enmType == Type_File) 147 return u.File.cbProcessed; 308 * @param pObj DnD transfer object to get processed bytes for. 309 */ 310 uint64_t DnDTransferObjectGetProcessed(PDNDTRANSFEROBJECT pObj) 311 { 312 if (pObj->enmType == DNDTRANSFEROBJTYPE_FILE) 313 return pObj->u.File.cbProcessed; 148 314 149 315 return 0; … … 153 319 * Returns the file's logical size (in bytes). 154 320 * 155 * Note: Only applies if the object is of type DnD URIObject::Type_File.321 * Note: Only applies if the object is of type DnDTransferObjectType_File. 156 322 * 157 323 * @return The file's logical size (in bytes). 158 */ 159 uint64_t DnDURIObject::GetSize(void) const 160 { 161 if (m_enmType == Type_File) 162 return u.File.cbToProcess; 324 * @param pObj DnD transfer object to get size for. 325 */ 326 uint64_t DnDTransferObjectGetSize(PDNDTRANSFEROBJECT pObj) 327 { 328 if (pObj->enmType == DNDTRANSFEROBJTYPE_FILE) 329 return pObj->u.File.cbToProcess; 163 330 164 331 return 0; … … 166 333 167 334 /** 168 * Initializes the object with an expected object type and file path. 169 * 170 * @returns VBox status code. 171 * @param enmType Type we expect this object to be. 172 * @param strPathAbs Absolute path of file this object represents. Optional. 173 */ 174 int DnDURIObject::Init(Type enmType, const RTCString &strPathAbs /* = */) 175 { 176 AssertReturn(m_enmType == Type_Unknown, VERR_WRONG_ORDER); 177 178 int rc; 179 180 switch (enmType) 181 { 182 case Type_File: 183 { 184 u.File.hFile = NIL_RTFILE; 185 break; 186 } 187 188 case Type_Directory: 189 { 190 u.Dir.hDir = NIL_RTDIR; 191 break; 192 } 193 194 default: 195 break; 196 } 197 198 if (enmType != Type_Unknown) 199 { 200 AssertReturn(strPathAbs.isNotEmpty(), VERR_INVALID_PARAMETER); 201 RTCString strPathAbsCopy = strPathAbs; 202 rc = DnDPathConvert(strPathAbsCopy.mutableRaw(), strPathAbsCopy.capacity(), DNDPATHCONVERT_FLAGS_TO_NATIVE); 203 if (RT_SUCCESS(rc)) 204 { 205 m_enmType = enmType; 206 m_strPathAbs = strPathAbsCopy; 207 } 208 else 209 LogRel2(("DnD: Absolute file path for guest file on the host is now '%s'\n", strPathAbs.c_str())); 210 } 211 else 212 rc = VERR_INVALID_PARAMETER; 213 214 return rc; 335 * Returns the object's type. 336 * 337 * @return The object's type. 338 * @param pObj DnD transfer object to get type for. 339 */ 340 DNDTRANSFEROBJTYPE DnDTransferObjectGetType(PDNDTRANSFEROBJECT pObj) 341 { 342 return pObj->enmType; 215 343 } 216 344 … … 220 348 * 221 349 * @return True if complete, False if not. 222 */ 223 bool DnDURIObject::IsComplete(void) const 350 * @param pObj DnD transfer object to get completion status for. 351 */ 352 bool DnDTransferObjectIsComplete(PDNDTRANSFEROBJECT pObj) 224 353 { 225 354 bool fComplete; 226 355 227 switch ( m_enmType)228 { 229 case Type_File:230 Assert( u.File.cbProcessed <=u.File.cbToProcess);231 fComplete = u.File.cbProcessed ==u.File.cbToProcess;232 break; 233 234 case Type_Directory:356 switch (pObj->enmType) 357 { 358 case DNDTRANSFEROBJTYPE_FILE: 359 Assert(pObj->u.File.cbProcessed <= pObj->u.File.cbToProcess); 360 fComplete = pObj->u.File.cbProcessed == pObj->u.File.cbToProcess; 361 break; 362 363 case DNDTRANSFEROBJTYPE_DIRECTORY: 235 364 fComplete = true; 236 365 break; … … 246 375 /** 247 376 * Returns whether the object is in an open state or not. 248 */ 249 bool DnDURIObject::IsOpen(void) const 250 { 251 switch (m_enmType) 252 { 253 case Type_File: return RTFileIsValid(u.File.hFile); 254 case Type_Directory: return RTDirIsValid(u.Dir.hDir); 255 default: break; 377 * @param pObj DnD transfer object to get open status for. 378 */ 379 bool DnDTransferObjectIsOpen(PDNDTRANSFEROBJECT pObj) 380 { 381 switch (pObj->enmType) 382 { 383 case DNDTRANSFEROBJTYPE_FILE: return RTFileIsValid(pObj->u.File.hFile); 384 case DNDTRANSFEROBJTYPE_DIRECTORY: return RTDirIsValid(pObj->u.Dir.hDir); 385 default: break; 256 386 } 257 387 … … 263 393 * 264 394 * @return IPRT status code. 395 * @param pObj DnD transfer object to open. 265 396 * @param fOpen Open mode to use; only valid for file objects. 266 397 * @param fMode File mode to set; only valid for file objects. Depends on fOpen and and can be 0. 267 * @param fFlags Additional DnD URIobject flags.268 */ 269 int DnD URIObject::Open(uint64_t fOpen, RTFMODE fMode /* = 0 */,270 DNDURIOBJECTFLAGS fFlags /* = DNDURIOBJECT_FLAGS_NONE */) 271 { 398 * @param fFlags Additional DnD transfer object flags. 399 */ 400 int DnDTransferObjectOpen(PDNDTRANSFEROBJECT pObj, uint64_t fOpen, RTFMODE fMode, DNDTRANSFEROBJECTFLAGS fFlags) 401 { 402 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 272 403 AssertReturn(fOpen, VERR_INVALID_FLAGS); 273 404 /* fMode is optional. */ 274 AssertReturn(!(fFlags & ~DND URIOBJECT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);405 AssertReturn(!(fFlags & ~DNDTRANSFEROBJECT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 275 406 RT_NOREF1(fFlags); 276 407 277 408 int rc = VINF_SUCCESS; 278 409 279 if (fOpen) /* Opening mode specified? */ 280 { 281 LogFlowThisFunc(("strPath=%s, fOpen=0x%x, fMode=0x%x, fFlags=0x%x\n", 282 m_strPathAbs.c_str(), fOpen, fMode, fFlags)); 283 switch (m_enmType) 284 { 285 case Type_File: 410 LogFlowFunc(("pszPath=%s, fOpen=0x%x, fMode=0x%x, fFlags=0x%x\n", pObj->pszPath, fOpen, fMode, fFlags)); 411 412 switch (pObj->enmType) 413 { 414 case DNDTRANSFEROBJTYPE_FILE: 415 { 416 LogRel2(("DnD: Opening file '%s'\n", pObj->pszPath)); 417 418 /* 419 * Open files on the source with RTFILE_O_DENY_WRITE to prevent races 420 * where the OS writes to the file while the destination side transfers 421 * it over. 422 */ 423 rc = RTFileOpen(&pObj->u.File.hFile, pObj->pszPath, fOpen); 424 if (RT_SUCCESS(rc)) 286 425 { 287 LogRel2(("DnD: Opening file '%s'\n", m_strPathAbs.c_str())); 288 289 /* 290 * Open files on the source with RTFILE_O_DENY_WRITE to prevent races 291 * where the OS writes to the file while the destination side transfers 292 * it over. 293 */ 294 rc = RTFileOpen(&u.File.hFile, m_strPathAbs.c_str(), fOpen); 295 if (RT_SUCCESS(rc)) 426 if ( (fOpen & RTFILE_O_WRITE) /* Only set the file mode on write. */ 427 && fMode /* Some file mode to set specified? */) 296 428 { 297 if ( (fOpen & RTFILE_O_WRITE) /* Only set the file mode on write. */ 298 && fMode /* Some file mode to set specified? */) 299 { 300 rc = RTFileSetMode(u.File.hFile, fMode); 301 if (RT_FAILURE(rc)) 302 LogRel(("DnD: Setting mode %#x for file '%s' failed with %Rrc\n", fMode, m_strPathAbs.c_str(), rc)); 303 } 304 else if (fOpen & RTFILE_O_READ) 305 { 306 rc = queryInfoInternal(); 307 } 429 rc = RTFileSetMode(pObj->u.File.hFile, fMode); 430 if (RT_FAILURE(rc)) 431 LogRel(("DnD: Setting mode %#x for file '%s' failed with %Rrc\n", fMode, pObj->pszPath, rc)); 308 432 } 309 else 310 LogRel(("DnD: Opening file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc)); 311 312 if (RT_SUCCESS(rc)) 433 else if (fOpen & RTFILE_O_READ) 313 434 { 314 LogFlowThisFunc(("File cbObject=%RU64, fMode=0x%x\n", 315 u.File.objInfo.cbObject, u.File.objInfo.Attr.fMode)); 316 u.File.cbToProcess = u.File.objInfo.cbObject; 317 u.File.cbProcessed = 0; 435 rc = dndTransferObjectQueryInfoInternal(pObj); 318 436 } 319 320 break;321 437 } 322 323 case Type_Directory: 438 else 439 LogRel(("DnD: Opening file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 440 441 if (RT_SUCCESS(rc)) 324 442 { 325 LogRel2(("DnD: Opening directory '%s'\n", m_strPathAbs.c_str())); 326 327 rc = RTDirOpen(&u.Dir.hDir, m_strPathAbs.c_str()); 328 if (RT_SUCCESS(rc)) 329 { 330 rc = queryInfoInternal(); 331 } 332 else 333 LogRel(("DnD: Opening directory '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc)); 334 break; 443 LogFlowFunc(("File cbObject=%RU64, fMode=0x%x\n", 444 pObj->u.File.objInfo.cbObject, pObj->u.File.objInfo.Attr.fMode)); 445 pObj->u.File.cbToProcess = pObj->u.File.objInfo.cbObject; 446 pObj->u.File.cbProcessed = 0; 335 447 } 336 448 337 default: 338 rc = VERR_NOT_IMPLEMENTED; 339 break; 340 } 449 break; 450 } 451 452 case DNDTRANSFEROBJTYPE_DIRECTORY: 453 { 454 LogRel2(("DnD: Opening directory '%s'\n", pObj->pszPath)); 455 456 rc = RTDirOpen(&pObj->u.Dir.hDir, pObj->pszPath); 457 if (RT_SUCCESS(rc)) 458 { 459 rc = dndTransferObjectQueryInfoInternal(pObj); 460 } 461 else 462 LogRel(("DnD: Opening directory '%s' failed with %Rrc\n", pObj->pszPath, rc)); 463 break; 464 } 465 466 default: 467 rc = VERR_NOT_IMPLEMENTED; 468 break; 341 469 } 342 470 … … 349 477 * 350 478 * @return IPRT status code. 351 */ 352 int DnDURIObject::queryInfoInternal(void) 479 * @param pObj DnD transfer object to query info for. 480 */ 481 static int dndTransferObjectQueryInfoInternal(PDNDTRANSFEROBJECT pObj) 353 482 { 354 483 int rc; 355 484 356 switch ( m_enmType)357 { 358 case Type_File:359 AssertMsgReturn(RTFileIsValid( u.File.hFile), ("Object has invalid file handle\n"), VERR_INVALID_STATE);360 rc = RTFileQueryInfo( u.File.hFile, &u.File.objInfo, RTFSOBJATTRADD_NOTHING);361 break; 362 363 case Type_Directory:364 AssertMsgReturn(RTDirIsValid( u.Dir.hDir), ("Object has invalid directory handle\n"), VERR_INVALID_STATE);365 rc = RTDirQueryInfo( u.Dir.hDir, &u.Dir.objInfo, RTFSOBJATTRADD_NOTHING);485 switch (pObj->enmType) 486 { 487 case DNDTRANSFEROBJTYPE_FILE: 488 AssertMsgReturn(RTFileIsValid(pObj->u.File.hFile), ("Object has invalid file handle\n"), VERR_INVALID_STATE); 489 rc = RTFileQueryInfo(pObj->u.File.hFile, &pObj->u.File.objInfo, RTFSOBJATTRADD_NOTHING); 490 break; 491 492 case DNDTRANSFEROBJTYPE_DIRECTORY: 493 AssertMsgReturn(RTDirIsValid(pObj->u.Dir.hDir), ("Object has invalid directory handle\n"), VERR_INVALID_STATE); 494 rc = RTDirQueryInfo(pObj->u.Dir.hDir, &pObj->u.Dir.objInfo, RTFSOBJATTRADD_NOTHING); 366 495 break; 367 496 … … 372 501 373 502 if (RT_FAILURE(rc)) 374 LogRel(("DnD: Querying information for '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));503 LogRel(("DnD: Querying information for '%s' failed with %Rrc\n", pObj->pszPath, rc)); 375 504 376 505 return rc; … … 381 510 * 382 511 * @return IPRT status code. 383 */ 384 int DnDURIObject::QueryInfo(void) 385 { 386 return queryInfoInternal(); 387 } 388 389 /** 390 * Rebases an absolute URI path from an old path base to a new path base. 391 * This function is needed in order to transform path from the source side to the target side. 512 * @param pObj DnD transfer object to query info for. 513 */ 514 int DnDTransferObjectQueryInfo(PDNDTRANSFEROBJECT pObj) 515 { 516 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 517 return dndTransferObjectQueryInfoInternal(pObj); 518 } 519 520 /** 521 * Reads data from the object. Only applies to files objects. 392 522 * 393 523 * @return IPRT status code. 394 * @param strPathAbs Absolute URI path to rebase. 395 * @param strBaseOld Old base path to rebase from. 396 * @param strBaseNew New base path to rebase to. 397 * 398 ** @todo Put this into an own class like DnDURIPath : public RTCString? 399 */ 400 /* static */ 401 int DnDURIObject::RebaseURIPath(RTCString &strPathAbs, 402 const RTCString &strBaseOld /* = "" */, 403 const RTCString &strBaseNew /* = "" */) 404 { 405 char *pszPath = RTUriFilePath(strPathAbs.c_str()); 406 if (!pszPath) /* No URI? */ 407 pszPath = RTStrDup(strPathAbs.c_str()); 408 409 int rc; 410 411 if (pszPath) 412 { 413 const char *pszPathStart = pszPath; 414 const char *pszBaseOld = strBaseOld.c_str(); 415 if ( pszBaseOld 416 && RTPathStartsWith(pszPath, pszBaseOld)) 417 { 418 pszPathStart += strlen(pszBaseOld); 419 } 420 421 rc = VINF_SUCCESS; 422 423 if (RT_SUCCESS(rc)) 424 { 425 char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart); 426 if (pszPathNew) 427 { 428 rc = DnDPathValidate(pszPathNew, false /* fMustExist */); 429 if (RT_SUCCESS(rc)) 430 { 431 char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */, 432 pszPathNew /* pszPath */, 433 NULL /* pszQuery */, NULL /* pszFragment */); 434 if (pszPathURI) 435 { 436 LogFlowFunc(("Rebasing \"%s\" to \"%s\"\n", strPathAbs.c_str(), pszPathURI)); 437 438 strPathAbs = RTCString(pszPathURI) + "\r\n"; 439 RTStrFree(pszPathURI); 440 } 441 else 442 rc = VERR_INVALID_PARAMETER; 443 } 444 else 445 LogRel(("DnD: Path validation for '%s' failed with %Rrc\n", pszPathNew, rc)); 446 447 RTStrFree(pszPathNew); 448 } 449 else 450 rc = VERR_NO_MEMORY; 451 } 452 453 RTStrFree(pszPath); 454 } 455 else 456 rc = VERR_NO_MEMORY; 457 458 if (RT_FAILURE(rc)) 459 LogRel(("DnD: Rebasing absolute path '%s' (baseOld=%s, baseNew=%s) failed with %Rrc\n", 460 strPathAbs.c_str(), strBaseOld.c_str(), strBaseNew.c_str(), rc)); 461 462 return rc; 463 } 464 465 /** 466 * Reads data from the object. Only applies to files objects. 467 * 468 * @return IPRT status code. 524 * @param pObj DnD transfer object to read data from. 469 525 * @param pvBuf Buffer where to store the read data. 470 526 * @param cbBuf Size (in bytes) of the buffer. 471 527 * @param pcbRead Pointer where to store how many bytes were read. Optional. 472 528 */ 473 int DnDURIObject::Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead) 474 { 529 int DnDTransferObjectRead(PDNDTRANSFEROBJECT pObj, void *pvBuf, size_t cbBuf, uint32_t *pcbRead) 530 { 531 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 475 532 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 476 533 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); … … 480 537 481 538 int rc; 482 switch ( m_enmType)483 { 484 case Type_File:485 { 486 rc = RTFileRead( u.File.hFile, pvBuf, cbBuf, &cbRead);539 switch (pObj->enmType) 540 { 541 case DNDTRANSFEROBJTYPE_FILE: 542 { 543 rc = RTFileRead(pObj->u.File.hFile, pvBuf, cbBuf, &cbRead); 487 544 if (RT_SUCCESS(rc)) 488 545 { 489 u.File.cbProcessed += cbRead;490 Assert( u.File.cbProcessed <=u.File.cbToProcess);546 pObj->u.File.cbProcessed += cbRead; 547 Assert(pObj->u.File.cbProcessed <= pObj->u.File.cbToProcess); 491 548 492 549 /* End of file reached or error occurred? */ 493 if ( u.File.cbToProcess494 && u.File.cbProcessed ==u.File.cbToProcess)550 if ( pObj->u.File.cbToProcess 551 && pObj->u.File.cbProcessed == pObj->u.File.cbToProcess) 495 552 { 496 553 rc = VINF_EOF; … … 498 555 } 499 556 else 500 LogRel(("DnD: Reading from file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));501 break; 502 } 503 504 case Type_Directory:557 LogRel(("DnD: Reading from file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 558 break; 559 } 560 561 case DNDTRANSFEROBJTYPE_DIRECTORY: 505 562 { 506 563 rc = VINF_SUCCESS; … … 519 576 } 520 577 521 LogFlowFunc(("Returning strSourcePath=%s, cbRead=%zu, rc=%Rrc\n", m_strPathAbs.c_str(), cbRead, rc));578 LogFlowFunc(("Returning cbRead=%zu, rc=%Rrc\n", cbRead, rc)); 522 579 return rc; 523 580 } … … 525 582 /** 526 583 * Resets the object's state and closes all related handles. 527 */ 528 void DnDURIObject::Reset(void) 529 { 530 LogFlowThisFuncEnter(); 531 532 Close(); 533 534 m_enmType = Type_Unknown; 535 m_strPathAbs = ""; 536 537 RT_ZERO(u); 584 * 585 * @param pObj DnD transfer object to reset. 586 */ 587 void DnDTransferObjectReset(PDNDTRANSFEROBJECT pObj) 588 { 589 AssertPtrReturnVoid(pObj); 590 591 LogFlowFuncEnter(); 592 593 dndTransferObjectCloseInternal(pObj); 594 595 pObj->enmType = DNDTRANSFEROBJTYPE_UNKNOWN; 596 pObj->idxDst = 0; 597 598 RTStrFree(pObj->pszPath); 599 pObj->pszPath = NULL; 600 601 RT_ZERO(pObj->u); 538 602 } 539 603 … … 541 605 * Sets the bytes to process by the object. 542 606 * 543 * Note: Only applies if the object is of type DnD URIObject::Type_File.607 * Note: Only applies if the object is of type DnDTransferObjectType_File. 544 608 * 545 609 * @return IPRT return code. 546 * @param cbSize Size (in bytes) to process. 547 */ 548 int DnDURIObject::SetSize(uint64_t cbSize) 549 { 550 AssertReturn(m_enmType == Type_File, VERR_INVALID_PARAMETER); 610 * @param pObj DnD transfer object to set size for. 611 * @param cbSize Size (in bytes) to process. 612 */ 613 int DnDTransferObjectSetSize(PDNDTRANSFEROBJECT pObj, uint64_t cbSize) 614 { 615 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 616 AssertReturn(pObj->enmType == DNDTRANSFEROBJTYPE_FILE, VERR_INVALID_PARAMETER); 551 617 552 618 /** @todo Implement sparse file support here. */ 553 619 554 u.File.cbToProcess = cbSize;620 pObj->u.File.cbToProcess = cbSize; 555 621 return VINF_SUCCESS; 556 622 } … … 560 626 * 561 627 * @return IPRT status code. 628 * @param pObj DnD transfer object to write to. 562 629 * @param pvBuf Buffer of data to write. 563 630 * @param cbBuf Size (in bytes) of data to write. 564 631 * @param pcbWritten Pointer where to store how many bytes were written. Optional. 565 632 */ 566 int DnDURIObject::Write(const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten) 567 { 633 int DnDTransferObjectWrite(PDNDTRANSFEROBJECT pObj, const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten) 634 { 635 AssertPtrReturn(pObj, VERR_INVALID_POINTER); 568 636 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 569 637 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); … … 573 641 574 642 int rc; 575 switch ( m_enmType)576 { 577 case Type_File:578 { 579 rc = RTFileWrite( u.File.hFile, pvBuf, cbBuf, &cbWritten);643 switch (pObj->enmType) 644 { 645 case DNDTRANSFEROBJTYPE_FILE: 646 { 647 rc = RTFileWrite(pObj->u.File.hFile, pvBuf, cbBuf, &cbWritten); 580 648 if (RT_SUCCESS(rc)) 581 649 { 582 u.File.cbProcessed += cbWritten;650 pObj->u.File.cbProcessed += cbWritten; 583 651 } 584 652 else 585 LogRel(("DnD: Writing to file '%s' failed with %Rrc\n", m_strPathAbs.c_str(), rc));586 break; 587 } 588 589 case Type_Directory:653 LogRel(("DnD: Writing to file '%s' failed with %Rrc\n", pObj->pszPath, rc)); 654 break; 655 } 656 657 case DNDTRANSFEROBJTYPE_DIRECTORY: 590 658 { 591 659 rc = VINF_SUCCESS; … … 604 672 } 605 673 606 LogFlow ThisFunc(("Returning strSourcePathAbs=%s, cbWritten=%zu, rc=%Rrc\n", m_strPathAbs.c_str(), cbWritten, rc));674 LogFlowFunc(("Returning cbWritten=%zu, rc=%Rrc\n", cbWritten, rc)); 607 675 return rc; 608 676 } -
trunk/src/VBox/GuestHost/DragAndDrop/Makefile.kmk
r82968 r85371 19 19 include $(KBUILD_PATH)/subheader.kmk 20 20 21 ifdef VBOX_WITH_TESTCASES 22 include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk 23 endif 24 21 25 VBOX_DND_GUESTHOST_FILES := \ 22 26 DnDDroppedFiles.cpp \ 23 27 DnDMIME.cpp \ 24 28 DnDPath.cpp \ 25 DnD URIList.cpp \26 DnD URIObject.cpp29 DnDTransferObject.cpp \ 30 DnDTransferList.cpp 27 31 28 32 # -
trunk/src/VBox/Main/include/GuestDnDPrivate.h
r85121 r85371 82 82 83 83 /** 84 * Class for handling the (raw) meta data. 85 */ 86 class GuestDnDMetaData 87 { 88 public: 89 84 * Struct for handling the (raw) meta data. 85 */ 86 struct GuestDnDMetaData 87 { 90 88 GuestDnDMetaData(void) 91 89 : pvData(NULL) 92 90 , cbData(0) 93 , cb DataUsed(0) { }91 , cbAllocated(0) { } 94 92 95 93 virtual ~GuestDnDMetaData(void) … … 97 95 reset(); 98 96 } 99 100 public:101 97 102 98 uint32_t add(const void *pvDataAdd, uint32_t cbDataAdd) … … 108 104 AssertPtrReturn(pvDataAdd, 0); 109 105 110 int rc = resize(cb Data+ cbDataAdd);106 int rc = resize(cbAllocated + cbDataAdd); 111 107 if (RT_FAILURE(rc)) 112 108 return 0; 113 109 114 Assert(cb Data >= cbDataUsed+ cbDataAdd);115 memcpy((uint8_t *)pvData + cbData Used, pvDataAdd, cbDataAdd);116 117 cbData Used+= cbDataAdd;118 119 return cbData Add;110 Assert(cbAllocated >= cbData + cbDataAdd); 111 memcpy((uint8_t *)pvData + cbData, pvDataAdd, cbDataAdd); 112 113 cbData += cbDataAdd; 114 115 return cbData; 120 116 } 121 117 … … 133 129 void reset(void) 134 130 { 131 strFmt = ""; 132 135 133 if (pvData) 136 134 { 137 Assert(cb Data);135 Assert(cbAllocated); 138 136 RTMemFree(pvData); 139 137 pvData = NULL; 140 138 } 141 139 142 cbData = 0; 143 cbDataUsed = 0; 144 } 145 146 const void *getData(void) const { return pvData; } 147 148 void *getDataMutable(void) { return pvData; } 149 150 uint32_t getSize(void) const { return cbDataUsed; } 151 152 public: 153 154 int fromString(const RTCString &strData) 155 { 156 int rc = VINF_SUCCESS; 157 158 if (strData.isNotEmpty()) 159 { 160 const uint32_t cbStrData = (uint32_t)strData.length() + 1; /* Include terminating zero. */ 161 rc = resize(cbStrData); 162 if (RT_SUCCESS(rc)) 163 memcpy(pvData, strData.c_str(), cbStrData); 164 } 165 166 return rc; 167 } 168 169 int fromURIList(const DnDURIList &lstURI) 170 { 171 return fromString(lstURI.GetRootEntries()); 172 } 173 174 protected: 140 cbAllocated = 0; 141 cbData = 0; 142 } 175 143 176 144 int resize(uint32_t cbSize) … … 182 150 } 183 151 184 if (cbSize == cb Data)152 if (cbSize == cbAllocated) 185 153 return VINF_SUCCESS; 186 154 … … 189 157 190 158 void *pvTmp = NULL; 191 if (!cb Data)192 { 193 Assert(cbData Used== 0);159 if (!cbAllocated) 160 { 161 Assert(cbData == 0); 194 162 pvTmp = RTMemAllocZ(cbSize); 195 163 } … … 203 171 if (pvTmp) 204 172 { 205 pvData = pvTmp;206 cb Data= cbSize;173 pvData = pvTmp; 174 cbAllocated = cbSize; 207 175 return VINF_SUCCESS; 208 176 } … … 211 179 } 212 180 213 protected: 214 215 void *pvData;216 uint32_t cbData;217 uint32_t cbDataUsed;218 };219 220 /** 221 * Class for keeping drag and drop (meta) data 222 * to be sent/received. 223 */ 224 class GuestDnDData 225 { 226 public: 227 181 /** Format string of this meta data. */ 182 com::Utf8Str strFmt; 183 /** Pointer to allocated meta data. */ 184 void *pvData; 185 /** Used bytes of meta data. Must not exceed cbAllocated. */ 186 uint32_t cbData; 187 /** Size (in bytes) of allocated meta data. */ 188 uint32_t cbAllocated; 189 }; 190 191 /** 192 * Struct for accounting shared DnD data to be sent/received. 193 */ 194 struct GuestDnDData 195 { 228 196 GuestDnDData(void) 229 : cbEstTotal(0) 230 , cbEstMeta(0) 231 , cbProcessed(0) 232 { 233 RT_ZERO(dataHdr); 234 } 197 : cbExtra(0) 198 , cbProcessed(0) { } 235 199 236 200 virtual ~GuestDnDData(void) … … 239 203 } 240 204 241 public:242 243 205 uint64_t addProcessed(uint32_t cbDataAdd) 244 206 { 245 const uint64_t cbTotal = getTotal(); NOREF(cbTotal);207 const uint64_t cbTotal = Meta.cbData + cbExtra; 246 208 Assert(cbProcessed + cbDataAdd <= cbTotal); 247 209 cbProcessed += cbDataAdd; … … 251 213 bool isComplete(void) const 252 214 { 253 const uint64_t cbTotal = getTotal();215 const uint64_t cbTotal = Meta.cbData + cbExtra; 254 216 LogFlowFunc(("cbProcessed=%RU64, cbTotal=%RU64\n", cbProcessed, cbTotal)); 255 217 Assert(cbProcessed <= cbTotal); … … 257 219 } 258 220 259 void *getChkSumMutable(void) { return dataHdr.pvChecksum; }260 261 uint32_t getChkSumSize(void) const { return dataHdr.cbChecksum; }262 263 void *getFmtMutable(void) { return dataHdr.pvMetaFmt; }264 265 uint32_t getFmtSize(void) const { return dataHdr.cbMetaFmt; }266 267 GuestDnDMetaData &getMeta(void) { return dataMeta; }268 269 221 uint8_t getPercentComplete(void) const 270 222 { 271 int64_t cbTotal = RT_MAX(getTotal(), 1); 272 return (uint8_t)(cbProcessed * 100 / cbTotal); 273 } 274 275 uint64_t getProcessed(void) const { return cbProcessed; } 223 const uint64_t cbTotal = Meta.cbData + cbExtra; 224 return (uint8_t)(cbProcessed * 100 / RT_MAX(cbTotal, 1)); 225 } 276 226 277 227 uint64_t getRemaining(void) const 278 228 { 279 const uint64_t cbTotal = getTotal();280 Assert (cbProcessed <= cbTotal);229 const uint64_t cbTotal = Meta.cbData + cbExtra; 230 AssertReturn(cbProcessed <= cbTotal, 0); 281 231 return cbTotal - cbProcessed; 282 232 } 283 233 284 uint64_t getTotal(void) const { return cbEstTotal; } 234 uint64_t getTotal(void) const 235 { 236 return Meta.cbData + cbExtra; 237 } 285 238 286 239 void reset(void) 287 240 { 288 clearFmt(); 289 clearChkSum(); 290 291 RT_ZERO(dataHdr); 292 293 dataMeta.reset(); 294 295 cbEstTotal = 0; 296 cbEstMeta = 0; 241 Meta.reset(); 242 243 cbExtra = 0; 297 244 cbProcessed = 0; 298 245 } 299 246 300 int setFmt(const void *pvFmt, uint32_t cbFmt)301 {302 if (cbFmt)303 {304 AssertPtrReturn(pvFmt, VERR_INVALID_POINTER);305 void *pvFmtTmp = RTMemAlloc(cbFmt);306 if (!pvFmtTmp)307 return VERR_NO_MEMORY;308 309 clearFmt();310 311 memcpy(pvFmtTmp, pvFmt, cbFmt);312 313 dataHdr.pvMetaFmt = pvFmtTmp;314 dataHdr.cbMetaFmt = cbFmt;315 }316 else317 clearFmt();318 319 return VINF_SUCCESS;320 }321 322 void setEstimatedSize(uint64_t cbTotal, uint32_t cbMeta)323 {324 Assert(cbMeta <= cbTotal);325 326 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", cbTotal, cbMeta));327 328 cbEstTotal = cbTotal;329 cbEstMeta = cbMeta;330 }331 332 protected:333 334 void clearChkSum(void)335 {336 if (dataHdr.pvChecksum)337 {338 Assert(dataHdr.cbChecksum);339 RTMemFree(dataHdr.pvChecksum);340 dataHdr.pvChecksum = NULL;341 }342 343 dataHdr.cbChecksum = 0;344 }345 346 void clearFmt(void)347 {348 if (dataHdr.pvMetaFmt)349 {350 Assert(dataHdr.cbMetaFmt);351 RTMemFree(dataHdr.pvMetaFmt);352 dataHdr.pvMetaFmt = NULL;353 }354 355 dataHdr.cbMetaFmt = 0;356 }357 358 protected:359 360 /** The data header. */361 VBOXDNDDATAHDR dataHdr;362 247 /** For storing the actual meta data. 363 248 * This might be an URI list or just plain raw data, 364 249 * according to the format being sent. */ 365 GuestDnDMetaData dataMeta; 366 /** Estimated total data size when receiving data. */ 367 uint64_t cbEstTotal; 368 /** Estimated meta data size when receiving data. */ 369 uint32_t cbEstMeta; 250 GuestDnDMetaData Meta; 251 /** Extra data to send/receive (in bytes). Can be 0 for raw data. 252 * For (file) transfers this is the total size for all files. */ 253 uint64_t cbExtra; 370 254 /** Overall size (in bytes) of processed data. */ 371 255 uint64_t cbProcessed; … … 373 257 374 258 /** Initial object context state / no state set. */ 375 #define DND_OBJ CTX_STATE_NONE 0259 #define DND_OBJ_STATE_NONE 0 376 260 /** The header was received / sent. */ 377 #define DND_OBJ CTX_STATE_HAS_HDR RT_BIT(0)261 #define DND_OBJ_STATE_HAS_HDR RT_BIT(0) 378 262 /** Validation mask for object context state. */ 379 #define DND_OBJCTX_STATE_VALID_MASK UINT32_C(0x00000001) 380 381 /** 382 * Structure for keeping a DnDURIObject context around. 383 */ 384 class GuestDnDURIObjCtx 385 { 386 public: 387 388 GuestDnDURIObjCtx(void) 389 : pObjURI(NULL) 390 , fIntermediate(false) 391 , fState(DND_OBJCTX_STATE_NONE) { } 392 393 virtual ~GuestDnDURIObjCtx(void) 394 { 395 destroy(); 396 } 397 398 public: 399 400 int createIntermediate(DnDURIObject::Type enmType) 401 { 402 reset(); 403 404 int rc; 405 406 try 407 { 408 pObjURI = new DnDURIObject(enmType); 409 fIntermediate = true; 410 411 rc = VINF_SUCCESS; 412 } 413 catch (std::bad_alloc &) 414 { 415 rc = VERR_NO_MEMORY; 416 } 417 418 LogThisFunc(("Returning %Rrc\n", rc)); 419 return rc; 420 } 421 422 void destroy(void) 423 { 424 LogFlowThisFuncEnter(); 425 426 if ( pObjURI 427 && fIntermediate) 428 { 429 delete pObjURI; 430 } 431 432 pObjURI = NULL; 433 fIntermediate = false; 434 } 435 436 DnDURIObject *getObj(void) const { return pObjURI; } 437 438 bool isIntermediate(void) { return fIntermediate; } 439 440 bool isValid(void) const { return (pObjURI != NULL); } 441 442 /** Returns the current state. */ 443 uint32_t getState(void) const { return fState; } 444 445 void reset(void) 446 { 447 LogFlowThisFuncEnter(); 448 449 destroy(); 450 451 fIntermediate = false; 452 fState = DND_OBJCTX_STATE_NONE; 453 } 454 455 void setObj(DnDURIObject *pObj) 456 { 457 LogFlowThisFunc(("%p\n", pObj)); 458 459 destroy(); 460 461 pObjURI = pObj; 462 } 463 464 /** 465 * Sets the new state. 466 * 467 * @returns The new state, if set. 468 * @param fStateNew New state to set. 469 */ 470 uint32_t setState(uint32_t fStateNew) 471 { 472 AssertReturn(!(fStateNew & ~DND_OBJCTX_STATE_VALID_MASK), fState /* Return old state */); 473 fState = fStateNew; 474 return fState; 475 } 476 477 protected: 478 479 /** Pointer to current object being handled. */ 480 DnDURIObject *pObjURI; 481 /** Flag whether pObjURI needs deletion after use. */ 482 bool fIntermediate; 483 /** Internal context state, corresponding to DND_OBJCTX_STATE_XXX. */ 484 uint32_t fState; 485 /** @todo Add more statistics / information here. */ 486 }; 487 488 /** 489 * Structure for keeping around an URI (data) transfer. 490 */ 491 class GuestDnDURIData 492 { 493 494 public: 495 496 GuestDnDURIData(void) 263 #define DND_OBJ_STATE_VALID_MASK UINT32_C(0x00000001) 264 265 /** 266 * Class for keeping around DnD (file) transfer data. 267 */ 268 struct GuestDnDTransferData 269 { 270 271 public: 272 273 GuestDnDTransferData(void) 497 274 : cObjToProcess(0) 498 275 , cObjProcessed(0) … … 500 277 , cbScratchBuf(0) { } 501 278 502 virtual ~GuestDnDURIData(void) 279 virtual ~GuestDnDTransferData(void) 280 { 281 destroy(); 282 } 283 284 int init(size_t cbBuf = _64K) 285 { 286 reset(); 287 288 pvScratchBuf = RTMemAlloc(cbBuf); 289 if (!pvScratchBuf) 290 return VERR_NO_MEMORY; 291 292 cbScratchBuf = cbBuf; 293 return VINF_SUCCESS; 294 } 295 296 void destroy(void) 503 297 { 504 298 reset(); … … 513 307 } 514 308 515 DnDDroppedFiles &getDroppedFiles(void) { return droppedFiles; }516 517 DnDURIList &getURIList(void) { return lstURI; }518 519 int init(size_t cbBuf = _64K)520 {521 reset();522 523 pvScratchBuf = RTMemAlloc(cbBuf);524 if (!pvScratchBuf)525 return VERR_NO_MEMORY;526 527 cbScratchBuf = cbBuf;528 return VINF_SUCCESS;529 }530 531 bool isComplete(void) const532 {533 LogFlowFunc(("cObjProcessed=%RU64, cObjToProcess=%RU64\n", cObjProcessed, cObjToProcess));534 535 if (!cObjToProcess) /* Always return true if we don't have an object count. */536 return true;537 538 Assert(cObjProcessed <= cObjToProcess);539 return (cObjProcessed == cObjToProcess);540 }541 542 const void *getBuffer(void) const { return pvScratchBuf; }543 544 void *getBufferMutable(void) { return pvScratchBuf; }545 546 size_t getBufferSize(void) const { return cbScratchBuf; }547 548 GuestDnDURIObjCtx &getObj(uint64_t uID = 0)549 {550 RT_NOREF(uID);551 AssertMsg(uID == 0, ("Other objects than object 0 is not supported yet\n"));552 return objCtx;553 }554 555 GuestDnDURIObjCtx &getObjCurrent(void)556 {557 DnDURIObject *pCurObj = lstURI.First();558 if ( !lstURI.IsEmpty()559 && pCurObj)560 {561 /* Point the context object to the current DnDURIObject to process. */562 objCtx.setObj(pCurObj);563 }564 else565 objCtx.reset();566 567 return objCtx;568 }569 570 uint64_t getObjToProcess(void) const { return cObjToProcess; }571 572 uint64_t getObjProcessed(void) const { return cObjProcessed; }573 574 int processObject(const DnDURIObject &Obj)575 {576 int rc;577 578 /** @todo Find objct in lstURI first! */579 switch (Obj.GetType())580 {581 case DnDURIObject::Type_Directory:582 case DnDURIObject::Type_File:583 rc = VINF_SUCCESS;584 break;585 586 default:587 rc = VERR_NOT_IMPLEMENTED;588 break;589 }590 591 if (RT_SUCCESS(rc))592 {593 if (cObjToProcess)594 {595 cObjProcessed++;596 Assert(cObjProcessed <= cObjToProcess);597 }598 }599 600 return rc;601 }602 603 void removeObjCurrent(void)604 {605 if (cObjToProcess)606 {607 cObjProcessed++;608 Assert(cObjProcessed <= cObjToProcess);609 }610 611 lstURI.RemoveFirst();612 objCtx.reset();613 }614 615 309 void reset(void) 616 310 { … … 619 313 cObjToProcess = 0; 620 314 cObjProcessed = 0; 621 622 droppedFiles.Close(); 623 624 lstURI.Clear(); 625 objCtx.reset(); 626 } 627 628 void setEstimatedObjects(uint64_t cObjs) 629 { 630 Assert(cObjToProcess == 0); 631 cObjToProcess = cObjs; 632 LogFlowFunc(("cObjToProcess=%RU64\n", cObjs)); 633 } 634 635 public: 636 637 int fromLocalMetaData(const GuestDnDMetaData &Data) 638 { 639 reset(); 640 641 if (!Data.getSize()) 642 return VINF_SUCCESS; 643 644 char *pszList; 645 int rc = RTStrCurrentCPToUtf8(&pszList, (const char *)Data.getData()); 646 if (RT_FAILURE(rc)) 647 { 648 LogFlowThisFunc(("String conversion failed with rc=%Rrc\n", rc)); 649 return rc; 650 } 651 652 const size_t cbList = Data.getSize(); 653 LogFlowThisFunc(("metaData=%p, cbList=%zu\n", &Data, cbList)); 654 655 if (cbList) 656 { 657 RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n"); 658 if (!lstURIOrg.isEmpty()) 659 { 660 /* Note: All files to be transferred will be kept open during the entire DnD 661 * operation, also to keep the accounting right. */ 662 rc = lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN); 663 if (RT_SUCCESS(rc)) 664 cObjToProcess = lstURI.GetTotalCount(); 665 } 666 } 667 668 RTStrFree(pszList); 669 return rc; 670 } 671 672 int fromRemoteMetaData(const GuestDnDMetaData &Data) 673 { 674 LogFlowFuncEnter(); 675 676 int rc = lstURI.SetFromURIData(Data.getData(), Data.getSize(), 0 /* uFlags */); 677 if (RT_SUCCESS(rc)) 678 { 679 const size_t cRootCount = lstURI.GetRootCount(); 680 LogFlowFunc(("cRootCount=%zu, cObjToProcess=%RU64\n", cRootCount, cObjToProcess)); 681 if (cRootCount > cObjToProcess) 682 rc = VERR_INVALID_PARAMETER; 683 } 684 685 return rc; 686 } 687 688 int toMetaData(std::vector<BYTE> &vecData) 689 { 690 const char *pszDroppedFilesDir = droppedFiles.GetDirAbs(); 691 692 Utf8Str strURIs = lstURI.GetRootEntries(RTCString(pszDroppedFilesDir)); 693 size_t cbData = strURIs.length(); 694 695 LogFlowFunc(("%zu root URIs (%zu bytes)\n", lstURI.GetRootCount(), cbData)); 696 697 int rc; 698 699 try 700 { 701 vecData.resize(cbData + 1 /* Include termination */); 702 memcpy(&vecData.front(), strURIs.c_str(), cbData); 703 704 rc = VINF_SUCCESS; 705 } 706 catch (std::bad_alloc &) 707 { 708 rc = VERR_NO_MEMORY; 709 } 710 711 return rc; 712 } 713 714 protected: 715 716 int processDirectory(const char *pszPath, uint32_t fMode) 717 { 718 /** @todo Find directory in lstURI first! */ 719 int rc; 720 721 const char *pszDroppedFilesDir = droppedFiles.GetDirAbs(); 722 char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath); 723 if (pszDir) 724 { 725 rc = RTDirCreateFullPath(pszDir, fMode); 726 if (cObjToProcess) 727 { 728 cObjProcessed++; 729 Assert(cObjProcessed <= cObjToProcess); 730 } 731 732 RTStrFree(pszDir); 733 } 734 else 735 rc = VERR_NO_MEMORY; 736 737 return rc; 738 } 739 740 protected: 315 } 316 317 bool isComplete(void) const 318 { 319 return (cObjProcessed == cObjToProcess); 320 } 741 321 742 322 /** Number of objects to process. */ 743 uint64_t 323 uint64_t cObjToProcess; 744 324 /** Number of objects already processed. */ 745 uint64_t cObjProcessed; 746 /** Handles all drop files for this operation. */ 747 DnDDroppedFiles droppedFiles; 748 /** (Non-recursive) List of URI objects to handle. */ 749 DnDURIList lstURI; 750 /** Context to current object being handled. 751 * As we currently do all transfers one after another we 752 * only have one context at a time. */ 753 GuestDnDURIObjCtx objCtx; 325 uint64_t cObjProcessed; 754 326 /** Pointer to an optional scratch buffer to use for 755 327 * doing the actual chunk transfers. */ 756 void 328 void *pvScratchBuf; 757 329 /** Size (in bytes) of scratch buffer. */ 758 size_t cbScratchBuf; 330 size_t cbScratchBuf; 331 }; 332 333 struct GuestDnDTransferSendData : public GuestDnDTransferData 334 { 335 GuestDnDTransferSendData() 336 : mfObjState(0) { } 337 338 virtual ~GuestDnDTransferSendData() 339 { 340 destroy(); 341 } 342 343 void destroy(void) 344 { 345 DnDTransferListDestroy(&mList); 346 } 347 348 void reset(void) 349 { 350 DnDTransferListReset(&mList); 351 mfObjState = 0; 352 353 GuestDnDTransferData::reset(); 354 } 355 356 /** Transfer List to handle. */ 357 DNDTRANSFERLIST mList; 358 /** Current state of object in transfer. 359 * This is needed for keeping compatibility to old(er) DnD HGCM protocols. 360 * 361 * At the moment we only support transferring one object at a time. */ 362 uint32_t mfObjState; 759 363 }; 760 364 … … 762 366 * Context structure for sending data to the guest. 763 367 */ 764 struct GuestDnDSendCtx 368 struct GuestDnDSendCtx : public GuestDnDData 765 369 { 766 370 /** Pointer to guest target class this context belongs to. */ … … 775 379 /** Drag'n drop format requested by the guest. */ 776 380 com::Utf8Str mFmtReq; 777 /** Drag'n drop data to send. 778 * This can be arbitrary data or an URI list. */ 779 GuestDnDData mData; 780 /** URI data structure. */ 781 GuestDnDURIData mURI; 381 /** Transfer data structure. */ 382 GuestDnDTransferSendData mTransfer; 782 383 /** Callback event to use. */ 783 384 GuestDnDCallbackEvent mCBEvent; 784 385 }; 785 386 387 struct GuestDnDTransferRecvData : public GuestDnDTransferData 388 { 389 GuestDnDTransferRecvData() 390 { 391 RT_ZERO(mDroppedFiles); 392 RT_ZERO(mList); 393 RT_ZERO(mObj); 394 } 395 396 virtual ~GuestDnDTransferRecvData() 397 { 398 destroy(); 399 } 400 401 void destroy(void) 402 { 403 DnDTransferListDestroy(&mList); 404 } 405 406 void reset(void) 407 { 408 DnDDroppedFilesClose(&mDroppedFiles); 409 DnDTransferListReset(&mList); 410 DnDTransferObjectReset(&mObj); 411 412 GuestDnDTransferData::reset(); 413 } 414 415 /** The "VirtualBox Dropped Files" directory on the host we're going 416 * to utilize for transferring files from guest to the host. */ 417 DNDDROPPEDFILES mDroppedFiles; 418 /** Transfer List to handle. 419 * Currently we only support one transfer list at a time. */ 420 DNDTRANSFERLIST mList; 421 /** Current transfer object being handled. 422 * Currently we only support one transfer object at a time. */ 423 DNDTRANSFEROBJECT mObj; 424 }; 425 786 426 /** 787 427 * Context structure for receiving data from the guest. 788 428 */ 789 struct GuestDnDRecvCtx 429 struct GuestDnDRecvCtx : public GuestDnDData 790 430 { 791 431 /** Pointer to guest source class this context belongs to. */ … … 813 453 * deleted e.g. when moving instead of copying. */ 814 454 VBOXDNDACTION mAction; 815 /** Drag'n drop received from the guest. 816 * This can be arbitrary data or an URI list. */ 817 GuestDnDData mData; 818 /** URI data structure. */ 819 GuestDnDURIData mURI; 455 /** Transfer data structure. */ 456 GuestDnDTransferRecvData mTransfer; 820 457 /** Callback event to use. */ 821 458 GuestDnDCallbackEvent mCBEvent; -
trunk/src/VBox/Main/include/GuestDnDSourceImpl.h
r85020 r85371 101 101 int i_receiveData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout); 102 102 int i_receiveRawData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout); 103 int i_receive URIData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout);103 int i_receiveTransferData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout); 104 104 105 105 protected: -
trunk/src/VBox/Main/include/GuestDnDTargetImpl.h
r85020 r85371 87 87 88 88 int i_sendData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout); 89 int i_sendDataBody(GuestDnDSendCtx *pCtx, GuestDnDData *pData); 90 int i_sendDataHeader(GuestDnDSendCtx *pCtx, GuestDnDData *pData, GuestDnDURIData *pURIData /* = NULL */); 91 int i_sendDirectory(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg); 92 int i_sendFile(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg); 93 int i_sendFileData(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg); 89 90 int i_sendMetaDataBody(GuestDnDSendCtx *pCtx); 91 int i_sendMetaDataHeader(GuestDnDSendCtx *pCtx); 92 93 int i_sendTransferData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout); 94 int i_sendTransferDataLoop(GuestDnDSendCtx *pCtx, GuestDnDMsg *pMsg); 95 96 int i_sendDirectory(GuestDnDSendCtx *pCtx, PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg); 97 int i_sendFile(GuestDnDSendCtx *pCtx, PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg); 98 int i_sendFileData(GuestDnDSendCtx *pCtx, PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg); 99 94 100 int i_sendRawData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout); 95 int i_sendURIData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout);96 int i_sendURIDataLoop(GuestDnDSendCtx *pCtx, GuestDnDMsg *pMsg);97 101 98 102 protected: … … 100 104 struct 101 105 { 106 /** Flag indicating whether a data transfer currently is active. */ 102 107 bool mfTransferIsPending; 103 108 /** Maximum data block size (in bytes) the target can handle. */ -
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.