Changeset 99951 in vbox for trunk/src/VBox/GuestHost/SharedClipboard
- Timestamp:
- May 24, 2023 10:37:12 AM (2 years ago)
- svn:sync-xref-src-repo-rev:
- 157609
- Location:
- trunk/src/VBox/GuestHost/SharedClipboard
- Files:
-
- 1 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/SharedClipboard/clipboard-transfers.cpp
r99937 r99951 47 47 static PSHCLTRANSFER shClTransferCtxGetTransferByIdInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uId); 48 48 static PSHCLTRANSFER shClTransferCtxGetTransferByIndexInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx); 49 static int shClConvertFileCreateFlags(uint32_t fShClFlags, uint64_t *pfOpen); 50 static int shClTransferResolvePathAbs(PSHCLTRANSFER pTransfer, const char *pszPath, uint32_t fFlags, char **ppszResolved); 51 static int shClTransferValidatePath(const char *pcszPath, bool fMustExist); 52 53 /** @todo Split this file up in different modules. */ 49 54 50 55 51 /** … … 578 574 } 579 575 580 int rc = shClTransferValidatePath(pszName, false /* fMustExist */);576 int rc = ShClTransferValidatePath(pszName, false /* fMustExist */); 581 577 if (RT_FAILURE(rc)) 582 578 return false; … … 840 836 * @param hObj Object handle of the object to get handle info for. 841 837 */ 842 DECLINLINE(PSHCLOBJHANDLEINFO) shClTransferObjGet(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj)838 PSHCLOBJHANDLEINFO ShClTransferObjGet(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj) 843 839 { 844 840 PSHCLOBJHANDLEINFO pIt; … … 874 870 875 871 int rc; 876 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL) 877 { 878 PSHCLOBJHANDLEINFO pInfo = (PSHCLOBJHANDLEINFO)RTMemAllocZ(sizeof(SHCLOBJHANDLEINFO)); 879 if (pInfo) 880 { 881 rc = ShClTransferObjHandleInfoInit(pInfo); 882 if (RT_SUCCESS(rc)) 883 { 884 uint64_t fOpen; 885 rc = shClConvertFileCreateFlags(pOpenCreateParms->fCreate, &fOpen); 886 if (RT_SUCCESS(rc)) 887 { 888 rc = shClTransferResolvePathAbs(pTransfer, pOpenCreateParms->pszPath, 0 /* fFlags */, 889 &pInfo->pszPathLocalAbs); 890 if (RT_SUCCESS(rc)) 891 { 892 rc = RTFileOpen(&pInfo->u.Local.hFile, pInfo->pszPathLocalAbs, fOpen); 893 if (RT_SUCCESS(rc)) 894 LogRel2(("Shared Clipboard: Opened file '%s'\n", pInfo->pszPathLocalAbs)); 895 else 896 LogRel(("Shared Clipboard: Error opening file '%s': rc=%Rrc\n", pInfo->pszPathLocalAbs, rc)); 897 } 898 } 899 } 900 901 if (RT_SUCCESS(rc)) 902 { 903 pInfo->hObj = pTransfer->uObjHandleNext++; 904 pInfo->enmType = SHCLOBJTYPE_FILE; 905 906 RTListAppend(&pTransfer->lstObj, &pInfo->Node); 907 pTransfer->cObjHandles++; 908 909 LogFlowFunc(("cObjHandles=%RU32\n", pTransfer->cObjHandles)); 910 911 *phObj = pInfo->hObj; 912 } 913 else 914 { 915 ShClTransferObjHandleInfoDestroy(pInfo); 916 RTMemFree(pInfo); 917 } 918 } 919 else 920 rc = VERR_NO_MEMORY; 921 } 922 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE) 923 { 924 if (pTransfer->ProviderIface.pfnObjOpen) 925 rc = pTransfer->ProviderIface.pfnObjOpen(&pTransfer->ProviderCtx, pOpenCreateParms, phObj); 926 else 927 rc = VERR_NOT_SUPPORTED; 928 } 872 if (pTransfer->ProviderIface.pfnObjOpen) 873 rc = pTransfer->ProviderIface.pfnObjOpen(&pTransfer->ProviderCtx, pOpenCreateParms, phObj); 929 874 else 930 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);875 rc = VERR_NOT_SUPPORTED; 931 876 932 877 LogFlowFuncLeaveRC(rc); … … 945 890 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 946 891 947 int rc = VINF_SUCCESS; 948 949 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL) 950 { 951 PSHCLOBJHANDLEINFO pInfo = shClTransferObjGet(pTransfer, hObj); 952 if (pInfo) 953 { 954 switch (pInfo->enmType) 955 { 956 case SHCLOBJTYPE_DIRECTORY: 957 { 958 rc = RTDirClose(pInfo->u.Local.hDir); 959 if (RT_SUCCESS(rc)) 960 { 961 pInfo->u.Local.hDir = NIL_RTDIR; 962 963 LogRel2(("Shared Clipboard: Closed directory '%s'\n", pInfo->pszPathLocalAbs)); 964 } 965 else 966 LogRel(("Shared Clipboard: Closing directory '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc)); 967 break; 968 } 969 970 case SHCLOBJTYPE_FILE: 971 { 972 rc = RTFileClose(pInfo->u.Local.hFile); 973 if (RT_SUCCESS(rc)) 974 { 975 pInfo->u.Local.hFile = NIL_RTFILE; 976 977 LogRel2(("Shared Clipboard: Closed file '%s'\n", pInfo->pszPathLocalAbs)); 978 } 979 else 980 LogRel(("Shared Clipboard: Closing file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc)); 981 break; 982 } 983 984 default: 985 rc = VERR_NOT_IMPLEMENTED; 986 break; 987 } 988 989 RTListNodeRemove(&pInfo->Node); 990 991 Assert(pTransfer->cObjHandles); 992 pTransfer->cObjHandles--; 993 994 ShClTransferObjHandleInfoDestroy(pInfo); 995 996 RTMemFree(pInfo); 997 pInfo = NULL; 998 } 999 else 1000 rc = VERR_NOT_FOUND; 1001 } 1002 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE) 1003 { 1004 if (pTransfer->ProviderIface.pfnObjClose) 1005 { 1006 rc = pTransfer->ProviderIface.pfnObjClose(&pTransfer->ProviderCtx, hObj); 1007 } 1008 else 1009 rc = VERR_NOT_SUPPORTED; 1010 } 892 int rc; 893 if (pTransfer->ProviderIface.pfnObjClose) 894 rc = pTransfer->ProviderIface.pfnObjClose(&pTransfer->ProviderCtx, hObj); 1011 895 else 1012 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);896 rc = VERR_NOT_SUPPORTED; 1013 897 1014 898 LogFlowFuncLeaveRC(rc); … … 1036 920 /** @todo Validate fFlags. */ 1037 921 1038 int rc = VINF_SUCCESS; 1039 1040 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL) 1041 { 1042 PSHCLOBJHANDLEINFO pInfo = shClTransferObjGet(pTransfer, hObj); 1043 if (pInfo) 1044 { 1045 switch (pInfo->enmType) 1046 { 1047 case SHCLOBJTYPE_FILE: 1048 { 1049 size_t cbRead; 1050 rc = RTFileRead(pInfo->u.Local.hFile, pvBuf, cbBuf, &cbRead); 1051 if (RT_SUCCESS(rc)) 1052 { 1053 if (pcbRead) 1054 *pcbRead = (uint32_t)cbRead; 1055 } 1056 break; 1057 } 1058 1059 default: 1060 rc = VERR_NOT_SUPPORTED; 1061 break; 1062 } 1063 } 1064 else 1065 rc = VERR_NOT_FOUND; 1066 } 1067 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE) 1068 { 1069 if (pTransfer->ProviderIface.pfnObjRead) 1070 { 1071 rc = pTransfer->ProviderIface.pfnObjRead(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbRead); 1072 } 1073 else 1074 rc = VERR_NOT_SUPPORTED; 1075 } 922 int rc; 923 if (pTransfer->ProviderIface.pfnObjRead) 924 rc = pTransfer->ProviderIface.pfnObjRead(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbRead); 1076 925 else 1077 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);926 rc = VERR_NOT_SUPPORTED; 1078 927 1079 928 LogFlowFuncLeaveRC(rc); … … 1100 949 /* pcbWritten is optional. */ 1101 950 1102 int rc = VINF_SUCCESS; 1103 1104 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL) 1105 { 1106 PSHCLOBJHANDLEINFO pInfo = shClTransferObjGet(pTransfer, hObj); 1107 if (pInfo) 1108 { 1109 switch (pInfo->enmType) 1110 { 1111 case SHCLOBJTYPE_FILE: 1112 { 1113 rc = RTFileWrite(pInfo->u.Local.hFile, pvBuf, cbBuf, (size_t *)pcbWritten); 1114 break; 1115 } 1116 1117 default: 1118 rc = VERR_NOT_SUPPORTED; 1119 break; 1120 } 1121 } 1122 else 1123 rc = VERR_NOT_FOUND; 1124 } 1125 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE) 1126 { 1127 if (pTransfer->ProviderIface.pfnObjWrite) 1128 { 1129 rc = pTransfer->ProviderIface.pfnObjWrite(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbWritten); 1130 } 1131 else 1132 rc = VERR_NOT_SUPPORTED; 1133 } 951 int rc; 952 if (pTransfer->ProviderIface.pfnObjWrite) 953 rc = pTransfer->ProviderIface.pfnObjWrite(&pTransfer->ProviderCtx, hObj, pvBuf, cbBuf, fFlags, pcbWritten); 1134 954 else 1135 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);955 rc = VERR_NOT_SUPPORTED; 1136 956 1137 957 LogFlowFuncLeaveRC(rc); … … 1376 1196 1377 1197 /** 1198 * Opens a transfer list. 1199 * 1200 * @returns VBox status code. 1201 * @param pTransfer Clipboard transfer to handle. 1202 * @param pOpenParms List open parameters to use for opening. 1203 * @param phList Where to store the List handle of opened list on success. 1204 */ 1205 int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms, 1206 PSHCLLISTHANDLE phList) 1207 { 1208 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1209 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER); 1210 AssertPtrReturn(phList, VERR_INVALID_POINTER); 1211 1212 if (pTransfer->cListHandles == pTransfer->cMaxListHandles) 1213 return VERR_SHCLPB_MAX_LISTS_REACHED; 1214 1215 int rc; 1216 if (pTransfer->ProviderIface.pfnListOpen) 1217 rc = pTransfer->ProviderIface.pfnListOpen(&pTransfer->ProviderCtx, pOpenParms, phList); 1218 else 1219 rc = VERR_NOT_SUPPORTED; 1220 1221 LogFlowFuncLeaveRC(rc); 1222 return rc; 1223 } 1224 1225 /** 1226 * Closes a transfer list. 1227 * 1228 * @returns VBox status code. 1229 * @param pTransfer Clipboard transfer to handle. 1230 * @param hList Handle of list to close. 1231 */ 1232 int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList) 1233 { 1234 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1235 1236 if (hList == NIL_SHCLLISTHANDLE) 1237 return VINF_SUCCESS; 1238 1239 int rc; 1240 if (pTransfer->ProviderIface.pfnListClose) 1241 rc = pTransfer->ProviderIface.pfnListClose(&pTransfer->ProviderCtx, hList); 1242 else 1243 rc = VERR_NOT_SUPPORTED; 1244 1245 LogFlowFuncLeaveRC(rc); 1246 return rc; 1247 } 1248 1249 /** 1250 * Retrieves the header of a transfer list. 1251 * 1252 * @returns VBox status code. 1253 * @param pTransfer Clipboard transfer to handle. 1254 * @param hList Handle of list to get header for. 1255 * @param pHdr Where to store the returned list header information. 1256 */ 1257 int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, 1258 PSHCLLISTHDR pHdr) 1259 { 1260 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1261 AssertPtrReturn(pHdr, VERR_INVALID_POINTER); 1262 1263 LogFlowFunc(("hList=%RU64\n", hList)); 1264 1265 int rc; 1266 if (pTransfer->ProviderIface.pfnListHdrRead) 1267 rc = pTransfer->ProviderIface.pfnListHdrRead(&pTransfer->ProviderCtx, hList, pHdr); 1268 else 1269 rc = VERR_NOT_SUPPORTED; 1270 1271 LogFlowFuncLeaveRC(rc); 1272 return rc; 1273 } 1274 1275 /** 1378 1276 * Returns a specific list handle info of a clipboard transfer. 1379 1277 * … … 1382 1280 * @param hList List handle of the list to get handle info for. 1383 1281 */ 1384 DECLINLINE(PSHCLLISTHANDLEINFO) shClTransferListGetByHandle(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)1282 PSHCLLISTHANDLEINFO ShClTransferListGetByHandle(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList) 1385 1283 { 1386 1284 PSHCLLISTHANDLEINFO pIt; … … 1395 1293 1396 1294 /** 1397 * Creates a new list handle (local only). 1398 * 1399 * @returns New List handle on success, or SHCLLISTHANDLE_INVALID on error. 1400 * @param pTransfer Clipboard transfer to create new list handle for. 1401 */ 1402 DECLINLINE(SHCLLISTHANDLE) shClTransferListHandleNew(PSHCLTRANSFER pTransfer) 1403 { 1404 return pTransfer->uListHandleNext++; /** @todo Good enough for now. Improve this later. */ 1295 * Returns the current transfer object of a transfer list. 1296 * 1297 * Currently not implemented and wil return NULL. 1298 * 1299 * @returns Pointer to transfer object, or NULL if not found / invalid. 1300 * @param pTransfer Clipboard transfer to return transfer object for. 1301 * @param hList Handle of clipboard transfer list to get object for. 1302 * @param uIdx Index of object to get. 1303 */ 1304 PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer, 1305 SHCLLISTHANDLE hList, uint64_t uIdx) 1306 { 1307 AssertPtrReturn(pTransfer, NULL); 1308 1309 RT_NOREF(hList, uIdx); 1310 1311 LogFlowFunc(("hList=%RU64\n", hList)); 1312 1313 return NULL; 1314 } 1315 1316 /** 1317 * Reads a single transfer list entry. 1318 * 1319 * @returns VBox status code or VERR_NO_MORE_FILES if the end of the list has been reached. 1320 * @param pTransfer Clipboard transfer to handle. 1321 * @param hList List handle of list to read from. 1322 * @param pEntry Where to store the read information. 1323 */ 1324 int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, 1325 PSHCLLISTENTRY pEntry) 1326 { 1327 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1328 AssertPtrReturn(pEntry, VERR_INVALID_POINTER); 1329 1330 LogFlowFunc(("hList=%RU64\n", hList)); 1331 1332 int rc; 1333 if (pTransfer->ProviderIface.pfnListEntryRead) 1334 rc = pTransfer->ProviderIface.pfnListEntryRead(&pTransfer->ProviderCtx, hList, pEntry); 1335 else 1336 rc = VERR_NOT_SUPPORTED; 1337 1338 LogFlowFuncLeaveRC(rc); 1339 return rc; 1340 } 1341 1342 int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, 1343 PSHCLLISTENTRY pEntry) 1344 { 1345 RT_NOREF(pTransfer, hList, pEntry); 1346 1347 int rc = VINF_SUCCESS; 1348 1349 #if 0 1350 if (pTransfer->ProviderIface.pfnListEntryWrite) 1351 rc = pTransfer->ProviderIface.pfnListEntryWrite(&pTransfer->ProviderCtx, hList, pEntry); 1352 #endif 1353 1354 LogFlowFuncLeaveRC(rc); 1355 return rc; 1356 } 1357 1358 /** 1359 * Returns whether a given transfer list handle is valid or not. 1360 * 1361 * @returns \c true if list handle is valid, \c false if not. 1362 * @param pTransfer Clipboard transfer to handle. 1363 * @param hList List handle to check. 1364 */ 1365 bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList) 1366 { 1367 bool fIsValid = false; 1368 1369 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL) 1370 { 1371 fIsValid = ShClTransferListGetByHandle(pTransfer, hList) != NULL; 1372 } 1373 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE) 1374 { 1375 AssertFailed(); /** @todo Implement. */ 1376 } 1377 else 1378 AssertFailedStmt(fIsValid = false); 1379 1380 return fIsValid; 1381 } 1382 1383 /** 1384 * Copies a transfer callback table from source to destination. 1385 * 1386 * @param pCallbacksDst Callback destination. 1387 * @param pCallbacksSrc Callback source. If set to NULL, the 1388 * destination callback table will be unset. 1389 */ 1390 void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst, 1391 PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc) 1392 { 1393 AssertPtrReturnVoid(pCallbacksDst); 1394 1395 if (pCallbacksSrc) /* Set */ 1396 { 1397 #define SET_CALLBACK(a_pfnCallback) \ 1398 if (pCallbacksSrc->a_pfnCallback) \ 1399 pCallbacksDst->a_pfnCallback = pCallbacksSrc->a_pfnCallback 1400 1401 SET_CALLBACK(pfnOnInitialize); 1402 SET_CALLBACK(pfnOnStart); 1403 SET_CALLBACK(pfnOnCompleted); 1404 SET_CALLBACK(pfnOnError); 1405 SET_CALLBACK(pfnOnRegistered); 1406 SET_CALLBACK(pfnOnUnregistered); 1407 1408 #undef SET_CALLBACK 1409 1410 pCallbacksDst->pvUser = pCallbacksSrc->pvUser; 1411 pCallbacksDst->cbUser = pCallbacksSrc->cbUser; 1412 } 1413 else /* Unset */ 1414 RT_BZERO(pCallbacksDst, sizeof(SHCLTRANSFERCALLBACKTABLE)); 1415 } 1416 1417 /** 1418 * Sets or unsets the callback table to be used for a clipboard transfer. 1419 * 1420 * @returns VBox status code. 1421 * @param pTransfer Clipboard transfer to set callbacks for. 1422 * @param pCallbacks Pointer to callback table to set. If set to NULL, 1423 * existing callbacks for this transfer will be unset. 1424 */ 1425 void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, 1426 PSHCLTRANSFERCALLBACKTABLE pCallbacks) 1427 { 1428 AssertPtrReturnVoid(pTransfer); 1429 /* pCallbacks can be NULL. */ 1430 1431 ShClTransferCopyCallbacks(&pTransfer->Callbacks, pCallbacks); 1432 } 1433 1434 /** 1435 * Sets the transfer provider interface for a given transfer. 1436 * 1437 * @returns VBox status code. 1438 * @param pTransfer Transfer to create transfer provider for. 1439 * @param pCreationCtx Provider creation context to use for provider creation. 1440 */ 1441 int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer, 1442 PSHCLTXPROVIDERCREATIONCTX pCreationCtx) 1443 { 1444 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1445 AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER); 1446 1447 LogFlowFuncEnter(); 1448 1449 int rc = VINF_SUCCESS; 1450 1451 pTransfer->ProviderIface = pCreationCtx->Interface; 1452 pTransfer->ProviderCtx.pTransfer = pTransfer; 1453 pTransfer->ProviderCtx.pvUser = pCreationCtx->pvUser; 1454 1455 LogFlowFuncLeaveRC(rc); 1456 return rc; 1457 } 1458 1459 /** 1460 * Clears (resets) the root list of a clipboard transfer. 1461 * 1462 * @param pTransfer Transfer to clear transfer root list for. 1463 */ 1464 static void shClTransferListRootsClear(PSHCLTRANSFER pTransfer) 1465 { 1466 AssertPtrReturnVoid(pTransfer); 1467 1468 if (pTransfer->pszPathRootAbs) 1469 { 1470 RTStrFree(pTransfer->pszPathRootAbs); 1471 pTransfer->pszPathRootAbs = NULL; 1472 } 1473 1474 PSHCLLISTROOT pListRoot, pListRootNext; 1475 RTListForEachSafe(&pTransfer->lstRoots, pListRoot, pListRootNext, SHCLLISTROOT, Node) 1476 { 1477 RTStrFree(pListRoot->pszPathAbs); 1478 1479 RTListNodeRemove(&pListRoot->Node); 1480 1481 RTMemFree(pListRoot); 1482 pListRoot = NULL; 1483 } 1484 1485 pTransfer->cRoots = 0; 1486 } 1487 1488 /** 1489 * Resets a clipboard transfer. 1490 * 1491 * @param pTransfer Clipboard transfer to reset. 1492 */ 1493 void ShClTransferReset(PSHCLTRANSFER pTransfer) 1494 { 1495 AssertPtrReturnVoid(pTransfer); 1496 1497 LogFlowFuncEnter(); 1498 1499 shClTransferListRootsClear(pTransfer); 1500 1501 PSHCLLISTHANDLEINFO pItList, pItListNext; 1502 RTListForEachSafe(&pTransfer->lstList, pItList, pItListNext, SHCLLISTHANDLEINFO, Node) 1503 { 1504 ShClTransferListHandleInfoDestroy(pItList); 1505 1506 RTListNodeRemove(&pItList->Node); 1507 1508 RTMemFree(pItList); 1509 } 1510 1511 PSHCLOBJHANDLEINFO pItObj, pItObjNext; 1512 RTListForEachSafe(&pTransfer->lstObj, pItObj, pItObjNext, SHCLOBJHANDLEINFO, Node) 1513 { 1514 ShClTransferObjHandleInfoDestroy(pItObj); 1515 1516 RTListNodeRemove(&pItObj->Node); 1517 1518 RTMemFree(pItObj); 1519 } 1520 } 1521 1522 /** 1523 * Returns the number of transfer root list entries. 1524 * 1525 * @returns Root list entry count. 1526 * @param pTransfer Clipboard transfer to return root entry count for. 1527 */ 1528 uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer) 1529 { 1530 AssertPtrReturn(pTransfer, 0); 1531 1532 LogFlowFunc(("[Transfer %RU32] cRoots=%RU64\n", pTransfer->State.uID, pTransfer->cRoots)); 1533 return (uint32_t)pTransfer->cRoots; 1534 } 1535 1536 /** 1537 * Returns a specific root list entry of a transfer. 1538 * 1539 * @returns Pointer to root list entry if found, or NULL if not found. 1540 * @param pTransfer Clipboard transfer to get root list entry from. 1541 * @param uIdx Index of root list entry to return. 1542 */ 1543 DECLINLINE(PSHCLLISTROOT) shClTransferRootsGetInternal(PSHCLTRANSFER pTransfer, uint32_t uIdx) 1544 { 1545 if (uIdx >= pTransfer->cRoots) 1546 return NULL; 1547 1548 PSHCLLISTROOT pIt = RTListGetFirst(&pTransfer->lstRoots, SHCLLISTROOT, Node); 1549 while (uIdx--) /** @todo Slow, but works for now. */ 1550 pIt = RTListGetNext(&pTransfer->lstRoots, pIt, SHCLLISTROOT, Node); 1551 1552 return pIt; 1553 } 1554 1555 /** 1556 * Get a specific root list entry. 1557 * 1558 * @returns VBox status code. 1559 * @param pTransfer Clipboard transfer to get root list entry of. 1560 * @param uIndex Index (zero-based) of entry to get. 1561 * @param pEntry Where to store the returned entry on success. 1562 */ 1563 int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer, 1564 uint64_t uIndex, PSHCLROOTLISTENTRY pEntry) 1565 { 1566 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1567 AssertPtrReturn(pEntry, VERR_INVALID_POINTER); 1568 1569 if (uIndex >= pTransfer->cRoots) 1570 return VERR_INVALID_PARAMETER; 1571 1572 int rc; 1573 1574 PSHCLLISTROOT pRoot = shClTransferRootsGetInternal(pTransfer, uIndex); 1575 AssertPtrReturn(pRoot, VERR_INVALID_PARAMETER); 1576 1577 const char *pcszSrcPathAbs = pRoot->pszPathAbs; 1578 1579 /* Make sure that we only advertise relative source paths, not absolute ones. */ 1580 char *pszFileName = RTPathFilename(pcszSrcPathAbs); 1581 if (pszFileName) 1582 { 1583 Assert(pszFileName >= pcszSrcPathAbs); 1584 size_t cchDstBase = pszFileName - pcszSrcPathAbs; 1585 const char *pszDstPath = &pcszSrcPathAbs[cchDstBase]; 1586 1587 LogFlowFunc(("pcszSrcPathAbs=%s, pszDstPath=%s\n", pcszSrcPathAbs, pszDstPath)); 1588 1589 rc = ShClTransferListEntryInitEx(pEntry, pszFileName); 1590 if (RT_SUCCESS(rc)) 1591 { 1592 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pszDstPath); 1593 if (RT_SUCCESS(rc)) 1594 { 1595 pEntry->cbInfo = sizeof(SHCLFSOBJINFO); 1596 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(pEntry->cbInfo); 1597 if (pEntry->pvInfo) 1598 { 1599 RTFSOBJINFO fsObjInfo; 1600 rc = RTPathQueryInfo(pcszSrcPathAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING); 1601 if (RT_SUCCESS(rc)) 1602 { 1603 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &fsObjInfo); 1604 1605 pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO; 1606 } 1607 } 1608 else 1609 rc = VERR_NO_MEMORY; 1610 } 1611 } 1612 } 1613 else 1614 rc = VERR_INVALID_POINTER; 1615 1616 LogFlowFuncLeaveRC(rc); 1617 return rc; 1618 } 1619 1620 /** 1621 * Returns the root entries of a clipboard transfer. 1622 * 1623 * @returns VBox status code. 1624 * @param pTransfer Clipboard transfer to return root entries for. 1625 * @param ppRootList Where to store the root list on success. 1626 */ 1627 int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList) 1628 { 1629 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1630 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER); 1631 1632 LogFlowFuncEnter(); 1633 1634 int rc; 1635 if (pTransfer->ProviderIface.pfnRootsGet) 1636 rc = pTransfer->ProviderIface.pfnRootsGet(&pTransfer->ProviderCtx, ppRootList); 1637 else 1638 rc = VERR_NOT_SUPPORTED; 1639 1640 LogFlowFuncLeaveRC(rc); 1641 return rc; 1642 } 1643 1644 /** 1645 * Sets root list entries for a given clipboard transfer. 1646 * 1647 * @returns VBox status code. 1648 * @param pTransfer Transfer to set transfer list entries for. 1649 * @param pszRoots String list (separated by CRLF) of root entries to set. 1650 * All entries must have the same root path. 1651 * @param cbRoots Size (in bytes) of string list. 1652 */ 1653 int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots) 1654 { 1655 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1656 AssertPtrReturn(pszRoots, VERR_INVALID_POINTER); 1657 AssertReturn(cbRoots, VERR_INVALID_PARAMETER); 1658 1659 if (!RTStrIsValidEncoding(pszRoots)) 1660 return VERR_INVALID_UTF8_ENCODING; 1661 1662 int rc = VINF_SUCCESS; 1663 1664 shClTransferListRootsClear(pTransfer); 1665 1666 char *pszPathRootAbs = NULL; 1667 1668 RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split("\r\n"); 1669 for (size_t i = 0; i < lstRootEntries.size(); ++i) 1670 { 1671 PSHCLLISTROOT pListRoot = (PSHCLLISTROOT)RTMemAlloc(sizeof(SHCLLISTROOT)); 1672 AssertPtrBreakStmt(pListRoot, rc = VERR_NO_MEMORY); 1673 1674 const char *pszPathCur = RTStrDup(lstRootEntries.at(i).c_str()); 1675 1676 LogFlowFunc(("pszPathCur=%s\n", pszPathCur)); 1677 1678 /* No root path determined yet? */ 1679 if (!pszPathRootAbs) 1680 { 1681 pszPathRootAbs = RTStrDup(pszPathCur); 1682 if (pszPathRootAbs) 1683 { 1684 RTPathStripFilename(pszPathRootAbs); 1685 1686 LogFlowFunc(("pszPathRootAbs=%s\n", pszPathRootAbs)); 1687 1688 /* We don't want to have a relative directory here. */ 1689 if (RTPathStartsWithRoot(pszPathRootAbs)) 1690 { 1691 rc = ShClTransferValidatePath(pszPathRootAbs, true /* Path must exist */); 1692 } 1693 else 1694 rc = VERR_INVALID_PARAMETER; 1695 } 1696 else 1697 rc = VERR_NO_MEMORY; 1698 } 1699 1700 if (RT_FAILURE(rc)) 1701 break; 1702 1703 pListRoot->pszPathAbs = RTStrDup(pszPathCur); 1704 if (!pListRoot->pszPathAbs) 1705 { 1706 rc = VERR_NO_MEMORY; 1707 break; 1708 } 1709 1710 RTListAppend(&pTransfer->lstRoots, &pListRoot->Node); 1711 1712 pTransfer->cRoots++; 1713 } 1714 1715 /* No (valid) root directory found? Bail out early. */ 1716 if (!pszPathRootAbs) 1717 rc = VERR_PATH_NOT_FOUND; 1718 1719 if (RT_SUCCESS(rc)) 1720 { 1721 /* 1722 * Step 2: 1723 * Go through the created list and make sure all entries have the same root path. 1724 */ 1725 PSHCLLISTROOT pListRoot; 1726 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node) 1727 { 1728 if (!RTStrStartsWith(pListRoot->pszPathAbs, pszPathRootAbs)) 1729 { 1730 rc = VERR_INVALID_PARAMETER; 1731 break; 1732 } 1733 1734 rc = ShClTransferValidatePath(pListRoot->pszPathAbs, true /* Path must exist */); 1735 if (RT_FAILURE(rc)) 1736 break; 1737 } 1738 } 1739 1740 /** @todo Entry rollback on failure? */ 1741 1742 if (RT_SUCCESS(rc)) 1743 { 1744 pTransfer->pszPathRootAbs = pszPathRootAbs; 1745 LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->cRoots)); 1746 1747 LogRel2(("Shared Clipboard: Transfer uses root '%s'\n", pTransfer->pszPathRootAbs)); 1748 } 1749 else 1750 { 1751 LogRel(("Shared Clipboard: Unable to set roots for transfer, rc=%Rrc\n", rc)); 1752 RTStrFree(pszPathRootAbs); 1753 } 1754 1755 LogFlowFuncLeaveRC(rc); 1756 return rc; 1757 } 1758 1759 /** 1760 * Sets a single file as a transfer root. 1761 * 1762 * @returns VBox status code. 1763 * @param pTransfer Transfer to set transfer list entries for. 1764 * @param pszFile File to use as transfer root. 1765 * 1766 * @note Convenience function, uses ShClTransferRootsSet() internally. 1767 */ 1768 int ShClTransferRootsSetAsFile(PSHCLTRANSFER pTransfer, const char *pszFile) 1769 { 1770 char *pszRoots = NULL; 1771 1772 int rc = RTStrAAppend(&pszRoots, pszFile); 1773 AssertRCReturn(rc, rc); 1774 rc = RTStrAAppend(&pszRoots, "\r\n"); 1775 AssertRCReturn(rc, rc); 1776 rc = ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1); 1777 RTStrFree(pszRoots); 1778 return rc; 1779 } 1780 1781 /** 1782 * Returns the clipboard transfer's ID. 1783 * 1784 * @returns The transfer's ID. 1785 * @param pTransfer Clipboard transfer to return ID for. 1786 */ 1787 SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer) 1788 { 1789 AssertPtrReturn(pTransfer, 0); 1790 1791 return pTransfer->State.uID; 1792 } 1793 1794 /** 1795 * Returns the clipboard transfer's direction. 1796 * 1797 * @returns The transfer's direction. 1798 * @param pTransfer Clipboard transfer to return direction for. 1799 */ 1800 SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer) 1801 { 1802 AssertPtrReturn(pTransfer, SHCLTRANSFERDIR_UNKNOWN); 1803 1804 LogFlowFunc(("[Transfer %RU32] enmDir=%RU32\n", pTransfer->State.uID, pTransfer->State.enmDir)); 1805 return pTransfer->State.enmDir; 1806 } 1807 1808 /** 1809 * Returns the absolute root path of a transfer. 1810 * 1811 * @returns VBox status code. 1812 * @param pTransfer Clipboard transfer to return absolute root path for. 1813 * @param pszPath Where to store the returned path. 1814 * @param cbPath Size (in bytes) of \a pszPath. 1815 */ 1816 int ShClTransferGetRootPathAbs(PSHCLTRANSFER pTransfer, char *pszPath, size_t cbPath) 1817 { 1818 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1819 1820 return RTStrCopy(pszPath, cbPath, pTransfer->pszPathRootAbs); 1821 } 1822 1823 /** 1824 * Returns the transfer's source. 1825 * 1826 * @returns The transfer's source. 1827 * @param pTransfer Clipboard transfer to return source for. 1828 */ 1829 SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer) 1830 { 1831 AssertPtrReturn(pTransfer, SHCLSOURCE_INVALID); 1832 1833 LogFlowFunc(("[Transfer %RU32] enmSource=%RU32\n", pTransfer->State.uID, pTransfer->State.enmSource)); 1834 return pTransfer->State.enmSource; 1835 } 1836 1837 /** 1838 * Returns the current transfer status. 1839 * 1840 * @returns Current transfer status. 1841 * @param pTransfer Clipboard transfer to return status for. 1842 */ 1843 SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer) 1844 { 1845 AssertPtrReturn(pTransfer, SHCLTRANSFERSTATUS_NONE); 1846 1847 LogFlowFunc(("[Transfer %RU32] enmStatus=%RU32\n", pTransfer->State.uID, pTransfer->State.enmStatus)); 1848 return pTransfer->State.enmStatus; 1849 } 1850 1851 /** 1852 * Runs a started clipboard transfer in a dedicated thread. 1853 * 1854 * @returns VBox status code. 1855 * @param pTransfer Clipboard transfer to run. 1856 * @param pfnThreadFunc Pointer to thread function to use. 1857 * @param pvUser Pointer to user-provided data. Optional. 1858 */ 1859 int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser) 1860 { 1861 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1862 AssertPtrReturn(pfnThreadFunc, VERR_INVALID_POINTER); 1863 /* pvUser is optional. */ 1864 1865 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_STARTED, 1866 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)), 1867 VERR_WRONG_ORDER); 1868 1869 int rc = shClTransferThreadCreate(pTransfer, pfnThreadFunc, pvUser); 1870 1871 LogFlowFuncLeaveRC(rc); 1872 return rc; 1873 } 1874 1875 /** 1876 * Starts an initialized transfer. 1877 * 1878 * @returns VBox status code. 1879 * @param pTransfer Clipboard transfer to start. 1880 */ 1881 int ShClTransferStart(PSHCLTRANSFER pTransfer) 1882 { 1883 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1884 1885 LogFlowFuncEnter(); 1886 1887 /* Ready to start? */ 1888 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_INITIALIZED, 1889 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)), 1890 VERR_WRONG_ORDER); 1891 1892 int rc; 1893 1894 if (pTransfer->Callbacks.pfnOnStart) 1895 { 1896 rc = pTransfer->Callbacks.pfnOnStart(&pTransfer->CallbackCtx); 1897 } 1898 else 1899 rc = VINF_SUCCESS; 1900 1901 if (RT_SUCCESS(rc)) 1902 { 1903 pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_STARTED; 1904 } 1905 1906 LogFlowFuncLeaveRC(rc); 1907 return rc; 1908 } 1909 1910 /** 1911 * Creates a thread for a clipboard transfer. 1912 * 1913 * @returns VBox status code. 1914 * @param pTransfer Clipboard transfer to create thread for. 1915 * @param pfnThreadFunc Thread function to use for this transfer. 1916 * @param pvUser Pointer to user-provided data. 1917 */ 1918 static int shClTransferThreadCreate(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser) 1919 1920 { 1921 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1922 1923 /* Already marked for stopping? */ 1924 AssertMsgReturn(pTransfer->Thread.fStop == false, 1925 ("Transfer thread already marked for stopping"), VERR_WRONG_ORDER); 1926 /* Already started? */ 1927 AssertMsgReturn(pTransfer->Thread.fStarted == false, 1928 ("Transfer thread already started"), VERR_WRONG_ORDER); 1929 1930 /* Spawn a worker thread, so that we don't block the window thread for too long. */ 1931 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc, 1932 pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, 1933 "shclp"); 1934 if (RT_SUCCESS(rc)) 1935 { 1936 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */); 1937 AssertRC(rc2); 1938 1939 if (pTransfer->Thread.fStarted) /* Did the thread indicate that it started correctly? */ 1940 { 1941 /* Nothing to do in here. */ 1942 } 1943 else 1944 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */ 1945 } 1946 1947 LogFlowFuncLeaveRC(rc); 1948 return rc; 1949 } 1950 1951 /** 1952 * Destroys the thread of a clipboard transfer. 1953 * 1954 * @returns VBox status code. 1955 * @param pTransfer Clipboard transfer to destroy thread for. 1956 * @param uTimeoutMs Timeout (in ms) to wait for thread creation. 1957 */ 1958 static int shClTransferThreadDestroy(PSHCLTRANSFER pTransfer, RTMSINTERVAL uTimeoutMs) 1959 { 1960 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 1961 1962 if (pTransfer->Thread.hThread == NIL_RTTHREAD) 1963 return VINF_SUCCESS; 1964 1965 LogFlowFuncEnter(); 1966 1967 /* Set stop indicator. */ 1968 pTransfer->Thread.fStop = true; 1969 1970 int rcThread = VERR_WRONG_ORDER; 1971 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread); 1972 1973 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread)); 1974 1975 return rc; 1976 } 1977 1978 /** 1979 * Initializes a clipboard transfer context. 1980 * 1981 * @returns VBox status code. 1982 * @param pTransferCtx Transfer context to initialize. 1983 */ 1984 int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx) 1985 { 1986 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER); 1987 1988 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx)); 1989 1990 int rc = RTCritSectInit(&pTransferCtx->CritSect); 1991 if (RT_SUCCESS(rc)) 1992 { 1993 RTListInit(&pTransferCtx->List); 1994 1995 pTransferCtx->cTransfers = 0; 1996 pTransferCtx->cRunning = 0; 1997 pTransferCtx->cMaxRunning = 64; /** @todo Make this configurable? */ 1998 1999 RT_ZERO(pTransferCtx->bmTransferIds); 2000 2001 ShClTransferCtxReset(pTransferCtx); 2002 } 2003 2004 return VINF_SUCCESS; 2005 } 2006 2007 /** 2008 * Destroys a clipboard transfer context. 2009 * 2010 * @param pTransferCtx Transfer context to destroy. 2011 */ 2012 void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx) 2013 { 2014 if (!pTransferCtx) 2015 return; 2016 2017 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx)); 2018 2019 if (RTCritSectIsInitialized(&pTransferCtx->CritSect)) 2020 RTCritSectDelete(&pTransferCtx->CritSect); 2021 2022 PSHCLTRANSFER pTransfer, pTransferNext; 2023 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node) 2024 { 2025 ShClTransferDestroy(pTransfer); 2026 2027 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer); 2028 2029 RTMemFree(pTransfer); 2030 pTransfer = NULL; 2031 } 2032 2033 pTransferCtx->cRunning = 0; 2034 pTransferCtx->cTransfers = 0; 2035 } 2036 2037 /** 2038 * Resets a clipboard transfer context. 2039 * 2040 * @param pTransferCtx Transfer context to reset. 2041 */ 2042 void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx) 2043 { 2044 AssertPtrReturnVoid(pTransferCtx); 2045 2046 LogFlowFuncEnter(); 2047 2048 PSHCLTRANSFER pTransfer; 2049 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) 2050 ShClTransferReset(pTransfer); 2051 2052 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP 2053 /** @todo Anything to do here? */ 2054 #endif 2055 } 2056 2057 /** 2058 * Returns a specific clipboard transfer, internal version. 2059 * 2060 * @returns Clipboard transfer found, or NULL if not found. 2061 * @param pTransferCtx Transfer context to return transfer for. 2062 * @param uID ID of the transfer to return. 2063 */ 2064 static PSHCLTRANSFER shClTransferCtxGetTransferByIdInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID) 2065 { 2066 PSHCLTRANSFER pTransfer; 2067 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) /** @todo Slow, but works for now. */ 2068 { 2069 if (pTransfer->State.uID == uID) 2070 return pTransfer; 2071 } 2072 2073 return NULL; 2074 } 2075 2076 /** 2077 * Returns a specific clipboard transfer by index, internal version. 2078 * 2079 * @returns Clipboard transfer found, or NULL if not found. 2080 * @param pTransferCtx Transfer context to return transfer for. 2081 * @param uIdx Index of the transfer to return. 2082 */ 2083 static PSHCLTRANSFER shClTransferCtxGetTransferByIndexInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx) 2084 { 2085 uint32_t idx = 0; 2086 2087 PSHCLTRANSFER pTransfer; 2088 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) /** @todo Slow, but works for now. */ 2089 { 2090 if (uIdx == idx) 2091 return pTransfer; 2092 idx++; 2093 } 2094 2095 return NULL; 2096 } 2097 2098 /** 2099 * Returns a clipboard transfer for a specific transfer ID. 2100 * 2101 * @returns Clipboard transfer found, or NULL if not found. 2102 * @param pTransferCtx Transfer context to return transfer for. 2103 * @param uID ID of the transfer to return. 2104 */ 2105 PSHCLTRANSFER ShClTransferCtxGetTransferById(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID) 2106 { 2107 return shClTransferCtxGetTransferByIdInternal(pTransferCtx, uID); 2108 } 2109 2110 /** 2111 * Returns a clipboard transfer for a specific list index. 2112 * 2113 * @returns Clipboard transfer found, or NULL if not found. 2114 * @param pTransferCtx Transfer context to return transfer for. 2115 * @param uIdx List index of the transfer to return. 2116 */ 2117 PSHCLTRANSFER ShClTransferCtxGetTransferByIndex(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx) 2118 { 2119 return shClTransferCtxGetTransferByIndexInternal(pTransferCtx, uIdx); 2120 } 2121 2122 /** 2123 * Returns the number of running clipboard transfers for a given transfer context. 2124 * 2125 * @returns Number of running transfers. 2126 * @param pTransferCtx Transfer context to return number for. 2127 */ 2128 uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx) 2129 { 2130 AssertPtrReturn(pTransferCtx, 0); 2131 return pTransferCtx->cRunning; 2132 } 2133 2134 /** 2135 * Returns the number of total clipboard transfers for a given transfer context. 2136 * 2137 * @returns Number of total transfers. 2138 * @param pTransferCtx Transfer context to return number for. 2139 */ 2140 uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx) 2141 { 2142 AssertPtrReturn(pTransferCtx, 0); 2143 return pTransferCtx->cTransfers; 2144 } 2145 2146 /** 2147 * Registers a clipboard transfer with a transfer context, i.e. allocates a transfer ID. 2148 * 2149 * @return VBox status code. 2150 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers 2151 * is reached. 2152 * @param pTransferCtx Transfer context to register transfer to. 2153 * @param pTransfer Transfer to register. The context takes ownership of the transfer on success. 2154 * @param pidTransfer Where to return the transfer ID on success. Optional. 2155 */ 2156 int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID *pidTransfer) 2157 { 2158 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER); 2159 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER); 2160 /* pidTransfer is optional. */ 2161 2162 /* 2163 * Pick a random bit as starting point. If it's in use, search forward 2164 * for a free one, wrapping around. We've reserved both the zero'th and 2165 * max-1 IDs. 2166 */ 2167 SHCLTRANSFERID idTransfer = RTRandU32Ex(1, VBOX_SHCL_MAX_TRANSFERS - 2); 2168 2169 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer)) 2170 { /* likely */ } 2171 else if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */) 2172 { 2173 /* Forward search. */ 2174 int iHit = ASMBitNextClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS, idTransfer); 2175 if (iHit < 0) 2176 iHit = ASMBitFirstClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS); 2177 AssertLogRelMsgReturn(iHit >= 0, ("Transfer count: %RU16\n", pTransferCtx->cTransfers), VERR_SHCLPB_MAX_TRANSFERS_REACHED); 2178 idTransfer = iHit; 2179 AssertLogRelMsgReturn(!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer), ("idObject=%#x\n", idTransfer), VERR_INTERNAL_ERROR_2); 2180 } 2181 else 2182 { 2183 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers)); 2184 return VERR_SHCLPB_MAX_TRANSFERS_REACHED; 2185 } 2186 2187 Log2Func(("pTransfer=%p, idTransfer=%RU32 (%RU16 transfers)\n", pTransfer, idTransfer, pTransferCtx->cTransfers)); 2188 2189 pTransfer->State.uID = idTransfer; 2190 2191 RTListAppend(&pTransferCtx->List, &pTransfer->Node); 2192 2193 pTransferCtx->cTransfers++; 2194 2195 if (pTransfer->Callbacks.pfnOnRegistered) 2196 pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx); 2197 2198 if (pidTransfer) 2199 *pidTransfer = idTransfer; 2200 2201 LogFlowFuncLeaveRC(VINF_SUCCESS); 2202 return VINF_SUCCESS; 2203 } 2204 2205 /** 2206 * Registers a clipboard transfer with a transfer context by specifying an ID for the transfer. 2207 * 2208 * @return VBox status code. 2209 * @retval VERR_ALREADY_EXISTS if a transfer with the given ID already exists. 2210 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers for this context has been reached. 2211 * @param pTransferCtx Transfer context to register transfer to. 2212 * @param pTransfer Transfer to register. 2213 * @param idTransfer Transfer ID to use for registration. 2214 */ 2215 int ShClTransferCtxTransferRegisterById(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID idTransfer) 2216 { 2217 LogFlowFunc(("cTransfers=%RU16, idTransfer=%RU32\n", pTransferCtx->cTransfers, idTransfer)); 2218 2219 if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */) 2220 { 2221 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer)) 2222 { 2223 RTListAppend(&pTransferCtx->List, &pTransfer->Node); 2224 2225 pTransfer->State.uID = idTransfer; 2226 2227 if (pTransfer->Callbacks.pfnOnRegistered) 2228 pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx); 2229 2230 pTransferCtx->cTransfers++; 2231 return VINF_SUCCESS; 2232 } 2233 2234 return VERR_ALREADY_EXISTS; 2235 } 2236 2237 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers)); 2238 return VERR_SHCLPB_MAX_TRANSFERS_REACHED; 2239 } 2240 2241 /** 2242 * Removes and unregisters a transfer from a transfer context. 2243 * 2244 * @param pTransferCtx Transfer context to remove transfer from. 2245 * @param pTransfer Transfer to remove. 2246 */ 2247 static void shclTransferCtxTransferRemoveAndUnregister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer) 2248 { 2249 RTListNodeRemove(&pTransfer->Node); 2250 2251 Assert(pTransferCtx->cTransfers); 2252 pTransferCtx->cTransfers--; 2253 2254 Assert(pTransferCtx->cTransfers >= pTransferCtx->cRunning); 2255 2256 if (pTransfer->Callbacks.pfnOnUnregistered) 2257 pTransfer->Callbacks.pfnOnUnregistered(&pTransfer->CallbackCtx, pTransferCtx); 2258 2259 LogFlowFunc(("Now %RU32 transfers left\n", pTransferCtx->cTransfers)); 2260 } 2261 2262 /** 2263 * Unregisters a transfer from an transfer context. 2264 * 2265 * @retval VINF_SUCCESS on success. 2266 * @retval VERR_NOT_FOUND if the transfer ID was not found. 2267 * @param pTransferCtx Transfer context to unregister transfer from. 2268 * @param idTransfer Transfer ID to unregister. 2269 */ 2270 int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer) 2271 { 2272 int rc = VINF_SUCCESS; 2273 AssertMsgStmt(ASMBitTestAndClear(&pTransferCtx->bmTransferIds, idTransfer), ("idTransfer=%#x\n", idTransfer), rc = VERR_NOT_FOUND); 2274 2275 LogFlowFunc(("idTransfer=%RU32\n", idTransfer)); 2276 2277 PSHCLTRANSFER pTransfer = shClTransferCtxGetTransferByIdInternal(pTransferCtx, idTransfer); 2278 if (pTransfer) 2279 { 2280 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer); 2281 } 2282 else 2283 rc = VERR_NOT_FOUND; 2284 2285 LogFlowFuncLeaveRC(rc); 2286 return rc; 2287 } 2288 2289 /** 2290 * Cleans up all associated transfers which are not needed (anymore). 2291 * This can be due to transfers which only have been announced but not / never being run. 2292 * 2293 * @param pTransferCtx Transfer context to cleanup transfers for. 2294 */ 2295 void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx) 2296 { 2297 AssertPtrReturnVoid(pTransferCtx); 2298 2299 LogFlowFunc(("pTransferCtx=%p, cTransfers=%RU16 cRunning=%RU16\n", 2300 pTransferCtx, pTransferCtx->cTransfers, pTransferCtx->cRunning)); 2301 2302 if (pTransferCtx->cTransfers == 0) 2303 return; 2304 2305 /* Remove all transfers which are not in a running state (e.g. only announced). */ 2306 PSHCLTRANSFER pTransfer, pTransferNext; 2307 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node) 2308 { 2309 if (ShClTransferGetStatus(pTransfer) != SHCLTRANSFERSTATUS_STARTED) 2310 { 2311 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer); 2312 2313 ShClTransferDestroy(pTransfer); 2314 2315 RTMemFree(pTransfer); 2316 pTransfer = NULL; 2317 } 2318 } 2319 } 2320 2321 /** 2322 * Returns whether the maximum of concurrent transfers of a specific transfer contexthas been reached or not. 2323 * 2324 * @returns \c if maximum has been reached, \c false if not. 2325 * @param pTransferCtx Transfer context to determine value for. 2326 */ 2327 bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx) 2328 { 2329 AssertPtrReturn(pTransferCtx, true); 2330 2331 LogFlowFunc(("cRunning=%RU32, cMaxRunning=%RU32\n", pTransferCtx->cRunning, pTransferCtx->cMaxRunning)); 2332 2333 Assert(pTransferCtx->cRunning <= pTransferCtx->cMaxRunning); 2334 return pTransferCtx->cRunning == pTransferCtx->cMaxRunning; 2335 } 2336 2337 /** 2338 * Copies file system objinfo from IPRT to Shared Clipboard format. 2339 * 2340 * @param pDst The Shared Clipboard structure to convert data to. 2341 * @param pSrc The IPRT structure to convert data from. 2342 */ 2343 void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc) 2344 { 2345 pDst->cbObject = pSrc->cbObject; 2346 pDst->cbAllocated = pSrc->cbAllocated; 2347 pDst->AccessTime = pSrc->AccessTime; 2348 pDst->ModificationTime = pSrc->ModificationTime; 2349 pDst->ChangeTime = pSrc->ChangeTime; 2350 pDst->BirthTime = pSrc->BirthTime; 2351 pDst->Attr.fMode = pSrc->Attr.fMode; 2352 /* Clear bits which we don't pass through for security reasons. */ 2353 pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT); 2354 RT_ZERO(pDst->Attr.u); 2355 switch (pSrc->Attr.enmAdditional) 2356 { 2357 default: 2358 case RTFSOBJATTRADD_NOTHING: 2359 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_NOTHING; 2360 break; 2361 2362 case RTFSOBJATTRADD_UNIX: 2363 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_UNIX; 2364 pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid; 2365 pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid; 2366 pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks; 2367 pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice; 2368 pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId; 2369 pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags; 2370 pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId; 2371 pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device; 2372 break; 2373 2374 case RTFSOBJATTRADD_EASIZE: 2375 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_EASIZE; 2376 pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb; 2377 break; 2378 } 2379 } 2380 2381 /** 2382 * Translates a clipboard transfer status (SHCLTRANSFERSTATUS_XXX) into a string. 2383 * 2384 * @returns Transfer status string name. 2385 * @param enmStatus The transfer status to translate. 2386 */ 2387 const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus) 2388 { 2389 switch (enmStatus) 2390 { 2391 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_NONE); 2392 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_INITIALIZED); 2393 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STARTED); 2394 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STOPPED); 2395 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_CANCELED); 2396 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_KILLED); 2397 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_ERROR); 2398 } 2399 return "Unknown"; 1405 2400 } 1406 2401 … … 1412 2407 * @param fMustExist Whether the path to validate also must exist. 1413 2408 */ 1414 static int shClTransferValidatePath(const char *pcszPath, bool fMustExist)2409 int ShClTransferValidatePath(const char *pcszPath, bool fMustExist) 1415 2410 { 1416 2411 int rc = VINF_SUCCESS; … … 1463 2458 } 1464 2459 1465 /**1466 * Resolves a relative path of a specific transfer to its absolute path.1467 *1468 * @returns VBox status code.1469 * @param pTransfer Clipboard transfer to resolve path for.1470 * @param pszPath Path to resolve.1471 * @param fFlags Resolve flags. Currently not used and must be 0.1472 * @param ppszResolved Where to store the allocated resolved path. Must be free'd by the called using RTStrFree().1473 */1474 static int shClTransferResolvePathAbs(PSHCLTRANSFER pTransfer, const char *pszPath, uint32_t fFlags,1475 char **ppszResolved)1476 {1477 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);1478 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);1479 AssertReturn (fFlags == 0, VERR_INVALID_PARAMETER);1480 1481 LogFlowFunc(("pszPathRootAbs=%s, pszPath=%s\n", pTransfer->pszPathRootAbs, pszPath));1482 1483 int rc = shClTransferValidatePath(pszPath, false /* fMustExist */);1484 if (RT_SUCCESS(rc))1485 {1486 char *pszPathAbs = RTPathJoinA(pTransfer->pszPathRootAbs, pszPath);1487 if (pszPathAbs)1488 {1489 char szResolved[RTPATH_MAX];1490 size_t cbResolved = sizeof(szResolved);1491 rc = RTPathAbsEx(pTransfer->pszPathRootAbs, pszPathAbs, RTPATH_STR_F_STYLE_HOST, szResolved, &cbResolved);1492 1493 RTStrFree(pszPathAbs);1494 1495 if (RT_SUCCESS(rc))1496 {1497 LogFlowFunc(("pszResolved=%s\n", szResolved));1498 1499 rc = VERR_PATH_NOT_FOUND; /* Play safe by default. */1500 1501 /* Make sure the resolved path is part of the set of root entries. */1502 PSHCLLISTROOT pListRoot;1503 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)1504 {1505 if (RTPathStartsWith(szResolved, pListRoot->pszPathAbs))1506 {1507 rc = VINF_SUCCESS;1508 break;1509 }1510 }1511 1512 if (RT_SUCCESS(rc))1513 *ppszResolved = RTStrDup(szResolved);1514 }1515 }1516 else1517 rc = VERR_NO_MEMORY;1518 }1519 1520 if (RT_FAILURE(rc))1521 LogRel(("Shared Clipboard: Resolving absolute path '%s' failed, rc=%Rrc\n", pszPath, rc));1522 1523 LogFlowFuncLeaveRC(rc);1524 return rc;1525 }1526 1527 /**1528 * Opens a transfer list.1529 *1530 * @returns VBox status code.1531 * @param pTransfer Clipboard transfer to handle.1532 * @param pOpenParms List open parameters to use for opening.1533 * @param phList Where to store the List handle of opened list on success.1534 */1535 int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms,1536 PSHCLLISTHANDLE phList)1537 {1538 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);1539 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);1540 AssertPtrReturn(phList, VERR_INVALID_POINTER);1541 1542 int rc;1543 1544 if (pTransfer->cListHandles == pTransfer->cMaxListHandles)1545 return VERR_SHCLPB_MAX_LISTS_REACHED;1546 1547 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)1548 {1549 LogFlowFunc(("pszPath=%s\n", pOpenParms->pszPath));1550 1551 PSHCLLISTHANDLEINFO pInfo1552 = (PSHCLLISTHANDLEINFO)RTMemAllocZ(sizeof(SHCLLISTHANDLEINFO));1553 if (pInfo)1554 {1555 rc = ShClTransferListHandleInfoInit(pInfo);1556 if (RT_SUCCESS(rc))1557 {1558 rc = shClTransferResolvePathAbs(pTransfer, pOpenParms->pszPath, 0 /* fFlags */, &pInfo->pszPathLocalAbs);1559 if (RT_SUCCESS(rc))1560 {1561 RTFSOBJINFO objInfo;1562 rc = RTPathQueryInfo(pInfo->pszPathLocalAbs, &objInfo, RTFSOBJATTRADD_NOTHING);1563 if (RT_SUCCESS(rc))1564 {1565 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))1566 {1567 rc = RTDirOpen(&pInfo->u.Local.hDir, pInfo->pszPathLocalAbs);1568 if (RT_SUCCESS(rc))1569 {1570 pInfo->enmType = SHCLOBJTYPE_DIRECTORY;1571 1572 LogRel2(("Shared Clipboard: Opening directory '%s'\n", pInfo->pszPathLocalAbs));1573 }1574 else1575 LogRel(("Shared Clipboard: Opening directory '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));1576 1577 }1578 else if (RTFS_IS_FILE(objInfo.Attr.fMode))1579 {1580 rc = RTFileOpen(&pInfo->u.Local.hFile, pInfo->pszPathLocalAbs,1581 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);1582 if (RT_SUCCESS(rc))1583 {1584 pInfo->enmType = SHCLOBJTYPE_FILE;1585 1586 LogRel2(("Shared Clipboard: Opening file '%s'\n", pInfo->pszPathLocalAbs));1587 }1588 else1589 LogRel(("Shared Clipboard: Opening file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));1590 }1591 else1592 rc = VERR_NOT_SUPPORTED;1593 1594 if (RT_SUCCESS(rc))1595 {1596 pInfo->hList = shClTransferListHandleNew(pTransfer);1597 1598 RTListAppend(&pTransfer->lstList, &pInfo->Node);1599 pTransfer->cListHandles++;1600 1601 if (phList)1602 *phList = pInfo->hList;1603 1604 LogFlowFunc(("pszPathLocalAbs=%s, hList=%RU64, cListHandles=%RU32\n",1605 pInfo->pszPathLocalAbs, pInfo->hList, pTransfer->cListHandles));1606 }1607 else1608 {1609 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))1610 {1611 if (RTDirIsValid(pInfo->u.Local.hDir))1612 RTDirClose(pInfo->u.Local.hDir);1613 }1614 else if (RTFS_IS_FILE(objInfo.Attr.fMode))1615 {1616 if (RTFileIsValid(pInfo->u.Local.hFile))1617 RTFileClose(pInfo->u.Local.hFile);1618 }1619 }1620 }1621 }1622 }1623 1624 if (RT_FAILURE(rc))1625 {1626 ShClTransferListHandleInfoDestroy(pInfo);1627 1628 RTMemFree(pInfo);1629 pInfo = NULL;1630 }1631 }1632 else1633 rc = VERR_NO_MEMORY;1634 }1635 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)1636 {1637 if (pTransfer->ProviderIface.pfnListOpen)1638 {1639 rc = pTransfer->ProviderIface.pfnListOpen(&pTransfer->ProviderCtx, pOpenParms, phList);1640 }1641 else1642 rc = VERR_NOT_SUPPORTED;1643 }1644 else1645 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);1646 1647 LogFlowFuncLeaveRC(rc);1648 return rc;1649 }1650 1651 /**1652 * Closes a transfer list.1653 *1654 * @returns VBox status code.1655 * @param pTransfer Clipboard transfer to handle.1656 * @param hList Handle of list to close.1657 */1658 int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)1659 {1660 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);1661 1662 if (hList == NIL_SHCLLISTHANDLE)1663 return VINF_SUCCESS;1664 1665 int rc = VINF_SUCCESS;1666 1667 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)1668 {1669 PSHCLLISTHANDLEINFO pInfo = shClTransferListGetByHandle(pTransfer, hList);1670 if (pInfo)1671 {1672 switch (pInfo->enmType)1673 {1674 case SHCLOBJTYPE_DIRECTORY:1675 {1676 if (RTDirIsValid(pInfo->u.Local.hDir))1677 {1678 RTDirClose(pInfo->u.Local.hDir);1679 pInfo->u.Local.hDir = NIL_RTDIR;1680 }1681 break;1682 }1683 1684 default:1685 rc = VERR_NOT_SUPPORTED;1686 break;1687 }1688 1689 RTListNodeRemove(&pInfo->Node);1690 1691 Assert(pTransfer->cListHandles);1692 pTransfer->cListHandles--;1693 1694 RTMemFree(pInfo);1695 }1696 else1697 rc = VERR_NOT_FOUND;1698 }1699 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)1700 {1701 if (pTransfer->ProviderIface.pfnListClose)1702 {1703 rc = pTransfer->ProviderIface.pfnListClose(&pTransfer->ProviderCtx, hList);1704 }1705 else1706 rc = VERR_NOT_SUPPORTED;1707 }1708 1709 LogFlowFuncLeaveRC(rc);1710 return rc;1711 }1712 1713 /**1714 * Adds a file to a transfer list header.1715 *1716 * @returns VBox status code.1717 * @param pHdr List header to add file to.1718 * @param pszPath Path of file to add.1719 */1720 static int shclTransferListHdrAddFile(PSHCLLISTHDR pHdr, const char *pszPath)1721 {1722 AssertPtrReturn(pHdr, VERR_INVALID_POINTER);1723 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);1724 1725 uint64_t cbSize = 0;1726 int rc = RTFileQuerySizeByPath(pszPath, &cbSize);1727 if (RT_SUCCESS(rc))1728 {1729 pHdr->cbTotalSize += cbSize;1730 pHdr->cTotalObjects++;1731 }1732 1733 LogFlowFuncLeaveRC(rc);1734 return rc;1735 }1736 1737 /**1738 * Builds a transfer list header, internal version.1739 *1740 * @returns VBox status code.1741 * @param pHdr Where to store the build list header.1742 * @param pcszPathAbs Absolute path to use for building the transfer list.1743 */1744 static int shclTransferListHdrFromDir(PSHCLLISTHDR pHdr, const char *pcszPathAbs)1745 {1746 AssertPtrReturn(pcszPathAbs, VERR_INVALID_POINTER);1747 1748 LogFlowFunc(("pcszPathAbs=%s\n", pcszPathAbs));1749 1750 RTFSOBJINFO objInfo;1751 int rc = RTPathQueryInfo(pcszPathAbs, &objInfo, RTFSOBJATTRADD_NOTHING);1752 if (RT_SUCCESS(rc))1753 {1754 if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))1755 {1756 RTDIR hDir;1757 rc = RTDirOpen(&hDir, pcszPathAbs);1758 if (RT_SUCCESS(rc))1759 {1760 size_t cbDirEntry = 0;1761 PRTDIRENTRYEX pDirEntry = NULL;1762 do1763 {1764 /* Retrieve the next directory entry. */1765 rc = RTDirReadExA(hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);1766 if (RT_FAILURE(rc))1767 {1768 if (rc == VERR_NO_MORE_FILES)1769 rc = VINF_SUCCESS;1770 break;1771 }1772 1773 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)1774 {1775 case RTFS_TYPE_DIRECTORY:1776 {1777 /* Skip "." and ".." entries. */1778 if (RTDirEntryExIsStdDotLink(pDirEntry))1779 break;1780 1781 pHdr->cTotalObjects++;1782 break;1783 }1784 case RTFS_TYPE_FILE:1785 {1786 char *pszSrc = RTPathJoinA(pcszPathAbs, pDirEntry->szName);1787 if (pszSrc)1788 {1789 rc = shclTransferListHdrAddFile(pHdr, pszSrc);1790 RTStrFree(pszSrc);1791 }1792 else1793 rc = VERR_NO_MEMORY;1794 break;1795 }1796 case RTFS_TYPE_SYMLINK:1797 {1798 /** @todo Not implemented yet. */1799 }1800 1801 default:1802 break;1803 }1804 1805 } while (RT_SUCCESS(rc));1806 1807 RTDirReadExAFree(&pDirEntry, &cbDirEntry);1808 RTDirClose(hDir);1809 }1810 }1811 else if (RTFS_IS_FILE(objInfo.Attr.fMode))1812 {1813 rc = shclTransferListHdrAddFile(pHdr, pcszPathAbs);1814 }1815 else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))1816 {1817 /** @todo Not implemented yet. */1818 }1819 else1820 rc = VERR_NOT_SUPPORTED;1821 }1822 1823 LogFlowFuncLeaveRC(rc);1824 return rc;1825 }1826 1827 /**1828 * Retrieves the header of a transfer list.1829 *1830 * @returns VBox status code.1831 * @param pTransfer Clipboard transfer to handle.1832 * @param hList Handle of list to get header for.1833 * @param pHdr Where to store the returned list header information.1834 */1835 int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,1836 PSHCLLISTHDR pHdr)1837 {1838 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);1839 AssertPtrReturn(pHdr, VERR_INVALID_POINTER);1840 1841 int rc;1842 1843 LogFlowFunc(("hList=%RU64\n", hList));1844 1845 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)1846 {1847 PSHCLLISTHANDLEINFO pInfo = shClTransferListGetByHandle(pTransfer, hList);1848 if (pInfo)1849 {1850 rc = ShClTransferListHdrInit(pHdr);1851 if (RT_SUCCESS(rc))1852 {1853 switch (pInfo->enmType)1854 {1855 case SHCLOBJTYPE_DIRECTORY:1856 {1857 LogFlowFunc(("DirAbs: %s\n", pInfo->pszPathLocalAbs));1858 1859 rc = shclTransferListHdrFromDir(pHdr, pInfo->pszPathLocalAbs);1860 break;1861 }1862 1863 case SHCLOBJTYPE_FILE:1864 {1865 LogFlowFunc(("FileAbs: %s\n", pInfo->pszPathLocalAbs));1866 1867 pHdr->cTotalObjects = 1;1868 1869 RTFSOBJINFO objInfo;1870 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);1871 if (RT_SUCCESS(rc))1872 {1873 pHdr->cbTotalSize = objInfo.cbObject;1874 }1875 break;1876 }1877 1878 default:1879 rc = VERR_NOT_SUPPORTED;1880 break;1881 }1882 }1883 1884 LogFlowFunc(("cTotalObj=%RU64, cbTotalSize=%RU64\n", pHdr->cTotalObjects, pHdr->cbTotalSize));1885 }1886 else1887 rc = VERR_NOT_FOUND;1888 }1889 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)1890 {1891 if (pTransfer->ProviderIface.pfnListHdrRead)1892 {1893 rc = pTransfer->ProviderIface.pfnListHdrRead(&pTransfer->ProviderCtx, hList, pHdr);1894 }1895 else1896 rc = VERR_NOT_SUPPORTED;1897 }1898 else1899 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);1900 1901 LogFlowFuncLeaveRC(rc);1902 return rc;1903 }1904 1905 /**1906 * Returns the current transfer object of a transfer list.1907 *1908 * Currently not implemented and wil return NULL.1909 *1910 * @returns Pointer to transfer object, or NULL if not found / invalid.1911 * @param pTransfer Clipboard transfer to return transfer object for.1912 * @param hList Handle of clipboard transfer list to get object for.1913 * @param uIdx Index of object to get.1914 */1915 PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer,1916 SHCLLISTHANDLE hList, uint64_t uIdx)1917 {1918 AssertPtrReturn(pTransfer, NULL);1919 1920 RT_NOREF(hList, uIdx);1921 1922 LogFlowFunc(("hList=%RU64\n", hList));1923 1924 return NULL;1925 }1926 1927 /**1928 * Reads a single transfer list entry.1929 *1930 * @returns VBox status code or VERR_NO_MORE_FILES if the end of the list has been reached.1931 * @param pTransfer Clipboard transfer to handle.1932 * @param hList List handle of list to read from.1933 * @param pEntry Where to store the read information.1934 */1935 int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,1936 PSHCLLISTENTRY pEntry)1937 {1938 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);1939 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);1940 1941 int rc = VINF_SUCCESS;1942 1943 LogFlowFunc(("hList=%RU64\n", hList));1944 1945 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)1946 {1947 PSHCLLISTHANDLEINFO pInfo = shClTransferListGetByHandle(pTransfer, hList);1948 if (pInfo)1949 {1950 switch (pInfo->enmType)1951 {1952 case SHCLOBJTYPE_DIRECTORY:1953 {1954 LogFlowFunc(("\tDirectory: %s\n", pInfo->pszPathLocalAbs));1955 1956 for (;;)1957 {1958 bool fSkipEntry = false; /* Whether to skip an entry in the enumeration. */1959 1960 size_t cbDirEntry = 0;1961 PRTDIRENTRYEX pDirEntry = NULL;1962 rc = RTDirReadExA(pInfo->u.Local.hDir, &pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);1963 if (RT_SUCCESS(rc))1964 {1965 switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)1966 {1967 case RTFS_TYPE_DIRECTORY:1968 {1969 /* Skip "." and ".." entries. */1970 if (RTDirEntryExIsStdDotLink(pDirEntry))1971 {1972 fSkipEntry = true;1973 break;1974 }1975 1976 LogFlowFunc(("Directory: %s\n", pDirEntry->szName));1977 break;1978 }1979 1980 case RTFS_TYPE_FILE:1981 {1982 LogFlowFunc(("File: %s\n", pDirEntry->szName));1983 break;1984 }1985 1986 case RTFS_TYPE_SYMLINK:1987 {1988 rc = VERR_NOT_IMPLEMENTED; /** @todo Not implemented yet. */1989 break;1990 }1991 1992 default:1993 break;1994 }1995 1996 if ( RT_SUCCESS(rc)1997 && !fSkipEntry)1998 {1999 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pDirEntry->szName);2000 if (RT_SUCCESS(rc))2001 {2002 pEntry->cbName = (uint32_t)strlen(pEntry->pszName) + 1; /* Include termination. */2003 2004 AssertPtr(pEntry->pvInfo);2005 Assert (pEntry->cbInfo == sizeof(SHCLFSOBJINFO));2006 2007 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &pDirEntry->Info);2008 2009 LogFlowFunc(("Entry pszName=%s, pvInfo=%p, cbInfo=%RU32\n",2010 pEntry->pszName, pEntry->pvInfo, pEntry->cbInfo));2011 }2012 }2013 2014 RTDirReadExAFree(&pDirEntry, &cbDirEntry);2015 }2016 2017 if ( !fSkipEntry /* Do we have a valid entry? Bail out. */2018 || RT_FAILURE(rc))2019 {2020 break;2021 }2022 }2023 2024 break;2025 }2026 2027 case SHCLOBJTYPE_FILE:2028 {2029 LogFlowFunc(("\tSingle file: %s\n", pInfo->pszPathLocalAbs));2030 2031 RTFSOBJINFO objInfo;2032 rc = RTFileQueryInfo(pInfo->u.Local.hFile, &objInfo, RTFSOBJATTRADD_NOTHING);2033 if (RT_SUCCESS(rc))2034 {2035 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(sizeof(SHCLFSOBJINFO));2036 if (pEntry->pvInfo)2037 {2038 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pInfo->pszPathLocalAbs);2039 if (RT_SUCCESS(rc))2040 {2041 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &objInfo);2042 2043 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);2044 pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;2045 }2046 }2047 else2048 rc = VERR_NO_MEMORY;2049 }2050 2051 break;2052 }2053 2054 default:2055 rc = VERR_NOT_SUPPORTED;2056 break;2057 }2058 }2059 else2060 rc = VERR_NOT_FOUND;2061 }2062 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)2063 {2064 if (pTransfer->ProviderIface.pfnListEntryRead)2065 rc = pTransfer->ProviderIface.pfnListEntryRead(&pTransfer->ProviderCtx, hList, pEntry);2066 else2067 rc = VERR_NOT_SUPPORTED;2068 }2069 else2070 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);2071 2072 LogFlowFuncLeaveRC(rc);2073 return rc;2074 }2075 2076 int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList,2077 PSHCLLISTENTRY pEntry)2078 {2079 RT_NOREF(pTransfer, hList, pEntry);2080 2081 int rc = VINF_SUCCESS;2082 2083 #if 02084 if (pTransfer->ProviderIface.pfnListEntryWrite)2085 rc = pTransfer->ProviderIface.pfnListEntryWrite(&pTransfer->ProviderCtx, hList, pEntry);2086 #endif2087 2088 LogFlowFuncLeaveRC(rc);2089 return rc;2090 }2091 2092 /**2093 * Returns whether a given transfer list handle is valid or not.2094 *2095 * @returns \c true if list handle is valid, \c false if not.2096 * @param pTransfer Clipboard transfer to handle.2097 * @param hList List handle to check.2098 */2099 bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)2100 {2101 bool fIsValid = false;2102 2103 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)2104 {2105 fIsValid = shClTransferListGetByHandle(pTransfer, hList) != NULL;2106 }2107 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)2108 {2109 AssertFailed(); /** @todo Implement. */2110 }2111 else2112 AssertFailedStmt(fIsValid = false);2113 2114 return fIsValid;2115 }2116 2117 /**2118 * Copies a transfer callback table from source to destination.2119 *2120 * @param pCallbacksDst Callback destination.2121 * @param pCallbacksSrc Callback source. If set to NULL, the2122 * destination callback table will be unset.2123 */2124 void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst,2125 PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc)2126 {2127 AssertPtrReturnVoid(pCallbacksDst);2128 2129 if (pCallbacksSrc) /* Set */2130 {2131 #define SET_CALLBACK(a_pfnCallback) \2132 if (pCallbacksSrc->a_pfnCallback) \2133 pCallbacksDst->a_pfnCallback = pCallbacksSrc->a_pfnCallback2134 2135 SET_CALLBACK(pfnOnInitialize);2136 SET_CALLBACK(pfnOnStart);2137 SET_CALLBACK(pfnOnCompleted);2138 SET_CALLBACK(pfnOnError);2139 SET_CALLBACK(pfnOnRegistered);2140 SET_CALLBACK(pfnOnUnregistered);2141 2142 #undef SET_CALLBACK2143 2144 pCallbacksDst->pvUser = pCallbacksSrc->pvUser;2145 pCallbacksDst->cbUser = pCallbacksSrc->cbUser;2146 }2147 else /* Unset */2148 RT_BZERO(pCallbacksDst, sizeof(SHCLTRANSFERCALLBACKTABLE));2149 }2150 2151 /**2152 * Sets or unsets the callback table to be used for a clipboard transfer.2153 *2154 * @returns VBox status code.2155 * @param pTransfer Clipboard transfer to set callbacks for.2156 * @param pCallbacks Pointer to callback table to set. If set to NULL,2157 * existing callbacks for this transfer will be unset.2158 */2159 void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer,2160 PSHCLTRANSFERCALLBACKTABLE pCallbacks)2161 {2162 AssertPtrReturnVoid(pTransfer);2163 /* pCallbacks can be NULL. */2164 2165 ShClTransferCopyCallbacks(&pTransfer->Callbacks, pCallbacks);2166 }2167 2168 /**2169 * Sets the transfer provider interface for a given transfer.2170 *2171 * @returns VBox status code.2172 * @param pTransfer Transfer to create transfer provider for.2173 * @param pCreationCtx Provider creation context to use for provider creation.2174 */2175 int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer,2176 PSHCLTXPROVIDERCREATIONCTX pCreationCtx)2177 {2178 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2179 AssertPtrReturn(pCreationCtx, VERR_INVALID_POINTER);2180 2181 LogFlowFuncEnter();2182 2183 int rc = VINF_SUCCESS;2184 2185 pTransfer->ProviderIface = pCreationCtx->Interface;2186 pTransfer->ProviderCtx.pTransfer = pTransfer;2187 pTransfer->ProviderCtx.pvUser = pCreationCtx->pvUser;2188 2189 LogFlowFuncLeaveRC(rc);2190 return rc;2191 }2192 2193 /**2194 * Clears (resets) the root list of a clipboard transfer.2195 *2196 * @param pTransfer Transfer to clear transfer root list for.2197 */2198 static void shClTransferListRootsClear(PSHCLTRANSFER pTransfer)2199 {2200 AssertPtrReturnVoid(pTransfer);2201 2202 if (pTransfer->pszPathRootAbs)2203 {2204 RTStrFree(pTransfer->pszPathRootAbs);2205 pTransfer->pszPathRootAbs = NULL;2206 }2207 2208 PSHCLLISTROOT pListRoot, pListRootNext;2209 RTListForEachSafe(&pTransfer->lstRoots, pListRoot, pListRootNext, SHCLLISTROOT, Node)2210 {2211 RTStrFree(pListRoot->pszPathAbs);2212 2213 RTListNodeRemove(&pListRoot->Node);2214 2215 RTMemFree(pListRoot);2216 pListRoot = NULL;2217 }2218 2219 pTransfer->cRoots = 0;2220 }2221 2222 /**2223 * Resets a clipboard transfer.2224 *2225 * @param pTransfer Clipboard transfer to reset.2226 */2227 void ShClTransferReset(PSHCLTRANSFER pTransfer)2228 {2229 AssertPtrReturnVoid(pTransfer);2230 2231 LogFlowFuncEnter();2232 2233 shClTransferListRootsClear(pTransfer);2234 2235 PSHCLLISTHANDLEINFO pItList, pItListNext;2236 RTListForEachSafe(&pTransfer->lstList, pItList, pItListNext, SHCLLISTHANDLEINFO, Node)2237 {2238 ShClTransferListHandleInfoDestroy(pItList);2239 2240 RTListNodeRemove(&pItList->Node);2241 2242 RTMemFree(pItList);2243 }2244 2245 PSHCLOBJHANDLEINFO pItObj, pItObjNext;2246 RTListForEachSafe(&pTransfer->lstObj, pItObj, pItObjNext, SHCLOBJHANDLEINFO, Node)2247 {2248 ShClTransferObjHandleInfoDestroy(pItObj);2249 2250 RTListNodeRemove(&pItObj->Node);2251 2252 RTMemFree(pItObj);2253 }2254 }2255 2256 /**2257 * Returns the number of transfer root list entries.2258 *2259 * @returns Root list entry count.2260 * @param pTransfer Clipboard transfer to return root entry count for.2261 */2262 uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer)2263 {2264 AssertPtrReturn(pTransfer, 0);2265 2266 LogFlowFunc(("[Transfer %RU32] cRoots=%RU64\n", pTransfer->State.uID, pTransfer->cRoots));2267 return (uint32_t)pTransfer->cRoots;2268 }2269 2270 /**2271 * Returns a specific root list entry of a transfer.2272 *2273 * @returns Pointer to root list entry if found, or NULL if not found.2274 * @param pTransfer Clipboard transfer to get root list entry from.2275 * @param uIdx Index of root list entry to return.2276 */2277 DECLINLINE(PSHCLLISTROOT) shClTransferRootsGetInternal(PSHCLTRANSFER pTransfer, uint32_t uIdx)2278 {2279 if (uIdx >= pTransfer->cRoots)2280 return NULL;2281 2282 PSHCLLISTROOT pIt = RTListGetFirst(&pTransfer->lstRoots, SHCLLISTROOT, Node);2283 while (uIdx--) /** @todo Slow, but works for now. */2284 pIt = RTListGetNext(&pTransfer->lstRoots, pIt, SHCLLISTROOT, Node);2285 2286 return pIt;2287 }2288 2289 /**2290 * Get a specific root list entry.2291 *2292 * @returns VBox status code.2293 * @param pTransfer Clipboard transfer to get root list entry of.2294 * @param uIndex Index (zero-based) of entry to get.2295 * @param pEntry Where to store the returned entry on success.2296 */2297 int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer,2298 uint64_t uIndex, PSHCLROOTLISTENTRY pEntry)2299 {2300 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2301 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);2302 2303 if (uIndex >= pTransfer->cRoots)2304 return VERR_INVALID_PARAMETER;2305 2306 int rc;2307 2308 PSHCLLISTROOT pRoot = shClTransferRootsGetInternal(pTransfer, uIndex);2309 AssertPtrReturn(pRoot, VERR_INVALID_PARAMETER);2310 2311 const char *pcszSrcPathAbs = pRoot->pszPathAbs;2312 2313 /* Make sure that we only advertise relative source paths, not absolute ones. */2314 char *pszFileName = RTPathFilename(pcszSrcPathAbs);2315 if (pszFileName)2316 {2317 Assert(pszFileName >= pcszSrcPathAbs);2318 size_t cchDstBase = pszFileName - pcszSrcPathAbs;2319 const char *pszDstPath = &pcszSrcPathAbs[cchDstBase];2320 2321 LogFlowFunc(("pcszSrcPathAbs=%s, pszDstPath=%s\n", pcszSrcPathAbs, pszDstPath));2322 2323 rc = ShClTransferListEntryInitEx(pEntry, pszFileName);2324 if (RT_SUCCESS(rc))2325 {2326 rc = RTStrCopy(pEntry->pszName, pEntry->cbName, pszDstPath);2327 if (RT_SUCCESS(rc))2328 {2329 pEntry->cbInfo = sizeof(SHCLFSOBJINFO);2330 pEntry->pvInfo = (PSHCLFSOBJINFO)RTMemAlloc(pEntry->cbInfo);2331 if (pEntry->pvInfo)2332 {2333 RTFSOBJINFO fsObjInfo;2334 rc = RTPathQueryInfo(pcszSrcPathAbs, &fsObjInfo, RTFSOBJATTRADD_NOTHING);2335 if (RT_SUCCESS(rc))2336 {2337 ShClFsObjFromIPRT(PSHCLFSOBJINFO(pEntry->pvInfo), &fsObjInfo);2338 2339 pEntry->fInfo = VBOX_SHCL_INFO_FLAG_FSOBJINFO;2340 }2341 }2342 else2343 rc = VERR_NO_MEMORY;2344 }2345 }2346 }2347 else2348 rc = VERR_INVALID_POINTER;2349 2350 LogFlowFuncLeaveRC(rc);2351 return rc;2352 }2353 2354 /**2355 * Returns the root entries of a clipboard transfer.2356 *2357 * @returns VBox status code.2358 * @param pTransfer Clipboard transfer to return root entries for.2359 * @param ppRootList Where to store the root list on success.2360 */2361 int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList)2362 {2363 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2364 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);2365 2366 LogFlowFuncEnter();2367 2368 int rc = VINF_SUCCESS;2369 2370 if (pTransfer->State.enmSource == SHCLSOURCE_LOCAL)2371 {2372 PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();2373 if (!pRootList)2374 return VERR_NO_MEMORY;2375 2376 const uint64_t cRoots = (uint32_t)pTransfer->cRoots;2377 2378 LogFlowFunc(("cRoots=%RU64\n", cRoots));2379 2380 if (cRoots)2381 {2382 PSHCLROOTLISTENTRY paRootListEntries2383 = (PSHCLROOTLISTENTRY)RTMemAllocZ(cRoots * sizeof(SHCLROOTLISTENTRY));2384 if (paRootListEntries)2385 {2386 for (uint64_t i = 0; i < cRoots; ++i)2387 {2388 rc = ShClTransferRootsEntry(pTransfer, i, &paRootListEntries[i]);2389 if (RT_FAILURE(rc))2390 break;2391 }2392 2393 if (RT_SUCCESS(rc))2394 pRootList->paEntries = paRootListEntries;2395 }2396 else2397 rc = VERR_NO_MEMORY;2398 }2399 else2400 rc = VERR_NOT_FOUND;2401 2402 if (RT_SUCCESS(rc))2403 {2404 pRootList->Hdr.cRoots = cRoots;2405 2406 *ppRootList = pRootList;2407 }2408 }2409 else if (pTransfer->State.enmSource == SHCLSOURCE_REMOTE)2410 {2411 if (pTransfer->ProviderIface.pfnRootsGet)2412 rc = pTransfer->ProviderIface.pfnRootsGet(&pTransfer->ProviderCtx, ppRootList);2413 else2414 rc = VERR_NOT_SUPPORTED;2415 }2416 else2417 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);2418 2419 LogFlowFuncLeaveRC(rc);2420 return rc;2421 }2422 2423 /**2424 * Sets root list entries for a given clipboard transfer.2425 *2426 * @returns VBox status code.2427 * @param pTransfer Transfer to set transfer list entries for.2428 * @param pszRoots String list (separated by CRLF) of root entries to set.2429 * All entries must have the same root path.2430 * @param cbRoots Size (in bytes) of string list.2431 */2432 int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots)2433 {2434 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2435 AssertPtrReturn(pszRoots, VERR_INVALID_POINTER);2436 AssertReturn(cbRoots, VERR_INVALID_PARAMETER);2437 2438 if (!RTStrIsValidEncoding(pszRoots))2439 return VERR_INVALID_UTF8_ENCODING;2440 2441 int rc = VINF_SUCCESS;2442 2443 shClTransferListRootsClear(pTransfer);2444 2445 char *pszPathRootAbs = NULL;2446 2447 RTCList<RTCString> lstRootEntries = RTCString(pszRoots, cbRoots - 1).split("\r\n");2448 for (size_t i = 0; i < lstRootEntries.size(); ++i)2449 {2450 PSHCLLISTROOT pListRoot = (PSHCLLISTROOT)RTMemAlloc(sizeof(SHCLLISTROOT));2451 AssertPtrBreakStmt(pListRoot, rc = VERR_NO_MEMORY);2452 2453 const char *pszPathCur = RTStrDup(lstRootEntries.at(i).c_str());2454 2455 LogFlowFunc(("pszPathCur=%s\n", pszPathCur));2456 2457 /* No root path determined yet? */2458 if (!pszPathRootAbs)2459 {2460 pszPathRootAbs = RTStrDup(pszPathCur);2461 if (pszPathRootAbs)2462 {2463 RTPathStripFilename(pszPathRootAbs);2464 2465 LogFlowFunc(("pszPathRootAbs=%s\n", pszPathRootAbs));2466 2467 /* We don't want to have a relative directory here. */2468 if (RTPathStartsWithRoot(pszPathRootAbs))2469 {2470 rc = shClTransferValidatePath(pszPathRootAbs, true /* Path must exist */);2471 }2472 else2473 rc = VERR_INVALID_PARAMETER;2474 }2475 else2476 rc = VERR_NO_MEMORY;2477 }2478 2479 if (RT_FAILURE(rc))2480 break;2481 2482 pListRoot->pszPathAbs = RTStrDup(pszPathCur);2483 if (!pListRoot->pszPathAbs)2484 {2485 rc = VERR_NO_MEMORY;2486 break;2487 }2488 2489 RTListAppend(&pTransfer->lstRoots, &pListRoot->Node);2490 2491 pTransfer->cRoots++;2492 }2493 2494 /* No (valid) root directory found? Bail out early. */2495 if (!pszPathRootAbs)2496 rc = VERR_PATH_NOT_FOUND;2497 2498 if (RT_SUCCESS(rc))2499 {2500 /*2501 * Step 2:2502 * Go through the created list and make sure all entries have the same root path.2503 */2504 PSHCLLISTROOT pListRoot;2505 RTListForEach(&pTransfer->lstRoots, pListRoot, SHCLLISTROOT, Node)2506 {2507 if (!RTStrStartsWith(pListRoot->pszPathAbs, pszPathRootAbs))2508 {2509 rc = VERR_INVALID_PARAMETER;2510 break;2511 }2512 2513 rc = shClTransferValidatePath(pListRoot->pszPathAbs, true /* Path must exist */);2514 if (RT_FAILURE(rc))2515 break;2516 }2517 }2518 2519 /** @todo Entry rollback on failure? */2520 2521 if (RT_SUCCESS(rc))2522 {2523 pTransfer->pszPathRootAbs = pszPathRootAbs;2524 LogFlowFunc(("pszPathRootAbs=%s, cRoots=%zu\n", pTransfer->pszPathRootAbs, pTransfer->cRoots));2525 2526 LogRel2(("Shared Clipboard: Transfer uses root '%s'\n", pTransfer->pszPathRootAbs));2527 }2528 else2529 {2530 LogRel(("Shared Clipboard: Unable to set roots for transfer, rc=%Rrc\n", rc));2531 RTStrFree(pszPathRootAbs);2532 }2533 2534 LogFlowFuncLeaveRC(rc);2535 return rc;2536 }2537 2538 /**2539 * Sets a single file as a transfer root.2540 *2541 * @returns VBox status code.2542 * @param pTransfer Transfer to set transfer list entries for.2543 * @param pszFile File to use as transfer root.2544 *2545 * @note Convenience function, uses ShClTransferRootsSet() internally.2546 */2547 int ShClTransferRootsSetAsFile(PSHCLTRANSFER pTransfer, const char *pszFile)2548 {2549 char *pszRoots = NULL;2550 2551 int rc = RTStrAAppend(&pszRoots, pszFile);2552 AssertRCReturn(rc, rc);2553 rc = RTStrAAppend(&pszRoots, "\r\n");2554 AssertRCReturn(rc, rc);2555 rc = ShClTransferRootsSet(pTransfer, pszRoots, strlen(pszRoots) + 1);2556 RTStrFree(pszRoots);2557 return rc;2558 }2559 2560 /**2561 * Returns the clipboard transfer's ID.2562 *2563 * @returns The transfer's ID.2564 * @param pTransfer Clipboard transfer to return ID for.2565 */2566 SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer)2567 {2568 AssertPtrReturn(pTransfer, 0);2569 2570 return pTransfer->State.uID;2571 }2572 2573 /**2574 * Returns the clipboard transfer's direction.2575 *2576 * @returns The transfer's direction.2577 * @param pTransfer Clipboard transfer to return direction for.2578 */2579 SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer)2580 {2581 AssertPtrReturn(pTransfer, SHCLTRANSFERDIR_UNKNOWN);2582 2583 LogFlowFunc(("[Transfer %RU32] enmDir=%RU32\n", pTransfer->State.uID, pTransfer->State.enmDir));2584 return pTransfer->State.enmDir;2585 }2586 2587 /**2588 * Returns the absolute root path of a transfer.2589 *2590 * @returns VBox status code.2591 * @param pTransfer Clipboard transfer to return absolute root path for.2592 * @param pszPath Where to store the returned path.2593 * @param cbPath Size (in bytes) of \a pszPath.2594 */2595 int ShClTransferGetRootPathAbs(PSHCLTRANSFER pTransfer, char *pszPath, size_t cbPath)2596 {2597 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2598 2599 return RTStrCopy(pszPath, cbPath, pTransfer->pszPathRootAbs);2600 }2601 2602 /**2603 * Returns the transfer's source.2604 *2605 * @returns The transfer's source.2606 * @param pTransfer Clipboard transfer to return source for.2607 */2608 SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer)2609 {2610 AssertPtrReturn(pTransfer, SHCLSOURCE_INVALID);2611 2612 LogFlowFunc(("[Transfer %RU32] enmSource=%RU32\n", pTransfer->State.uID, pTransfer->State.enmSource));2613 return pTransfer->State.enmSource;2614 }2615 2616 /**2617 * Returns the current transfer status.2618 *2619 * @returns Current transfer status.2620 * @param pTransfer Clipboard transfer to return status for.2621 */2622 SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer)2623 {2624 AssertPtrReturn(pTransfer, SHCLTRANSFERSTATUS_NONE);2625 2626 LogFlowFunc(("[Transfer %RU32] enmStatus=%RU32\n", pTransfer->State.uID, pTransfer->State.enmStatus));2627 return pTransfer->State.enmStatus;2628 }2629 2630 /**2631 * Runs a started clipboard transfer in a dedicated thread.2632 *2633 * @returns VBox status code.2634 * @param pTransfer Clipboard transfer to run.2635 * @param pfnThreadFunc Pointer to thread function to use.2636 * @param pvUser Pointer to user-provided data. Optional.2637 */2638 int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)2639 {2640 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2641 AssertPtrReturn(pfnThreadFunc, VERR_INVALID_POINTER);2642 /* pvUser is optional. */2643 2644 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_STARTED,2645 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),2646 VERR_WRONG_ORDER);2647 2648 int rc = shClTransferThreadCreate(pTransfer, pfnThreadFunc, pvUser);2649 2650 LogFlowFuncLeaveRC(rc);2651 return rc;2652 }2653 2654 /**2655 * Starts an initialized transfer.2656 *2657 * @returns VBox status code.2658 * @param pTransfer Clipboard transfer to start.2659 */2660 int ShClTransferStart(PSHCLTRANSFER pTransfer)2661 {2662 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2663 2664 LogFlowFuncEnter();2665 2666 /* Ready to start? */2667 AssertMsgReturn(pTransfer->State.enmStatus == SHCLTRANSFERSTATUS_INITIALIZED,2668 ("Wrong status (currently is %s)\n", ShClTransferStatusToStr(pTransfer->State.enmStatus)),2669 VERR_WRONG_ORDER);2670 2671 int rc;2672 2673 if (pTransfer->Callbacks.pfnOnStart)2674 {2675 rc = pTransfer->Callbacks.pfnOnStart(&pTransfer->CallbackCtx);2676 }2677 else2678 rc = VINF_SUCCESS;2679 2680 if (RT_SUCCESS(rc))2681 {2682 pTransfer->State.enmStatus = SHCLTRANSFERSTATUS_STARTED;2683 }2684 2685 LogFlowFuncLeaveRC(rc);2686 return rc;2687 }2688 2689 /**2690 * Creates a thread for a clipboard transfer.2691 *2692 * @returns VBox status code.2693 * @param pTransfer Clipboard transfer to create thread for.2694 * @param pfnThreadFunc Thread function to use for this transfer.2695 * @param pvUser Pointer to user-provided data.2696 */2697 static int shClTransferThreadCreate(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser)2698 2699 {2700 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2701 2702 /* Already marked for stopping? */2703 AssertMsgReturn(pTransfer->Thread.fStop == false,2704 ("Transfer thread already marked for stopping"), VERR_WRONG_ORDER);2705 /* Already started? */2706 AssertMsgReturn(pTransfer->Thread.fStarted == false,2707 ("Transfer thread already started"), VERR_WRONG_ORDER);2708 2709 /* Spawn a worker thread, so that we don't block the window thread for too long. */2710 int rc = RTThreadCreate(&pTransfer->Thread.hThread, pfnThreadFunc,2711 pvUser, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,2712 "shclp");2713 if (RT_SUCCESS(rc))2714 {2715 int rc2 = RTThreadUserWait(pTransfer->Thread.hThread, 30 * 1000 /* Timeout in ms */);2716 AssertRC(rc2);2717 2718 if (pTransfer->Thread.fStarted) /* Did the thread indicate that it started correctly? */2719 {2720 /* Nothing to do in here. */2721 }2722 else2723 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */2724 }2725 2726 LogFlowFuncLeaveRC(rc);2727 return rc;2728 }2729 2730 /**2731 * Destroys the thread of a clipboard transfer.2732 *2733 * @returns VBox status code.2734 * @param pTransfer Clipboard transfer to destroy thread for.2735 * @param uTimeoutMs Timeout (in ms) to wait for thread creation.2736 */2737 static int shClTransferThreadDestroy(PSHCLTRANSFER pTransfer, RTMSINTERVAL uTimeoutMs)2738 {2739 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2740 2741 if (pTransfer->Thread.hThread == NIL_RTTHREAD)2742 return VINF_SUCCESS;2743 2744 LogFlowFuncEnter();2745 2746 /* Set stop indicator. */2747 pTransfer->Thread.fStop = true;2748 2749 int rcThread = VERR_WRONG_ORDER;2750 int rc = RTThreadWait(pTransfer->Thread.hThread, uTimeoutMs, &rcThread);2751 2752 LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n", rc, rcThread));2753 2754 return rc;2755 }2756 2757 /**2758 * Initializes a clipboard transfer context.2759 *2760 * @returns VBox status code.2761 * @param pTransferCtx Transfer context to initialize.2762 */2763 int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx)2764 {2765 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);2766 2767 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx));2768 2769 int rc = RTCritSectInit(&pTransferCtx->CritSect);2770 if (RT_SUCCESS(rc))2771 {2772 RTListInit(&pTransferCtx->List);2773 2774 pTransferCtx->cTransfers = 0;2775 pTransferCtx->cRunning = 0;2776 pTransferCtx->cMaxRunning = 64; /** @todo Make this configurable? */2777 2778 RT_ZERO(pTransferCtx->bmTransferIds);2779 2780 ShClTransferCtxReset(pTransferCtx);2781 }2782 2783 return VINF_SUCCESS;2784 }2785 2786 /**2787 * Destroys a clipboard transfer context.2788 *2789 * @param pTransferCtx Transfer context to destroy.2790 */2791 void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx)2792 {2793 if (!pTransferCtx)2794 return;2795 2796 LogFlowFunc(("pTransferCtx=%p\n", pTransferCtx));2797 2798 if (RTCritSectIsInitialized(&pTransferCtx->CritSect))2799 RTCritSectDelete(&pTransferCtx->CritSect);2800 2801 PSHCLTRANSFER pTransfer, pTransferNext;2802 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)2803 {2804 ShClTransferDestroy(pTransfer);2805 2806 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer);2807 2808 RTMemFree(pTransfer);2809 pTransfer = NULL;2810 }2811 2812 pTransferCtx->cRunning = 0;2813 pTransferCtx->cTransfers = 0;2814 }2815 2816 /**2817 * Resets a clipboard transfer context.2818 *2819 * @param pTransferCtx Transfer context to reset.2820 */2821 void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx)2822 {2823 AssertPtrReturnVoid(pTransferCtx);2824 2825 LogFlowFuncEnter();2826 2827 PSHCLTRANSFER pTransfer;2828 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node)2829 ShClTransferReset(pTransfer);2830 2831 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP2832 /** @todo Anything to do here? */2833 #endif2834 }2835 2836 /**2837 * Returns a specific clipboard transfer, internal version.2838 *2839 * @returns Clipboard transfer found, or NULL if not found.2840 * @param pTransferCtx Transfer context to return transfer for.2841 * @param uID ID of the transfer to return.2842 */2843 static PSHCLTRANSFER shClTransferCtxGetTransferByIdInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID)2844 {2845 PSHCLTRANSFER pTransfer;2846 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) /** @todo Slow, but works for now. */2847 {2848 if (pTransfer->State.uID == uID)2849 return pTransfer;2850 }2851 2852 return NULL;2853 }2854 2855 /**2856 * Returns a specific clipboard transfer by index, internal version.2857 *2858 * @returns Clipboard transfer found, or NULL if not found.2859 * @param pTransferCtx Transfer context to return transfer for.2860 * @param uIdx Index of the transfer to return.2861 */2862 static PSHCLTRANSFER shClTransferCtxGetTransferByIndexInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx)2863 {2864 uint32_t idx = 0;2865 2866 PSHCLTRANSFER pTransfer;2867 RTListForEach(&pTransferCtx->List, pTransfer, SHCLTRANSFER, Node) /** @todo Slow, but works for now. */2868 {2869 if (uIdx == idx)2870 return pTransfer;2871 idx++;2872 }2873 2874 return NULL;2875 }2876 2877 /**2878 * Returns a clipboard transfer for a specific transfer ID.2879 *2880 * @returns Clipboard transfer found, or NULL if not found.2881 * @param pTransferCtx Transfer context to return transfer for.2882 * @param uID ID of the transfer to return.2883 */2884 PSHCLTRANSFER ShClTransferCtxGetTransferById(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID)2885 {2886 return shClTransferCtxGetTransferByIdInternal(pTransferCtx, uID);2887 }2888 2889 /**2890 * Returns a clipboard transfer for a specific list index.2891 *2892 * @returns Clipboard transfer found, or NULL if not found.2893 * @param pTransferCtx Transfer context to return transfer for.2894 * @param uIdx List index of the transfer to return.2895 */2896 PSHCLTRANSFER ShClTransferCtxGetTransferByIndex(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx)2897 {2898 return shClTransferCtxGetTransferByIndexInternal(pTransferCtx, uIdx);2899 }2900 2901 /**2902 * Returns the number of running clipboard transfers for a given transfer context.2903 *2904 * @returns Number of running transfers.2905 * @param pTransferCtx Transfer context to return number for.2906 */2907 uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx)2908 {2909 AssertPtrReturn(pTransferCtx, 0);2910 return pTransferCtx->cRunning;2911 }2912 2913 /**2914 * Returns the number of total clipboard transfers for a given transfer context.2915 *2916 * @returns Number of total transfers.2917 * @param pTransferCtx Transfer context to return number for.2918 */2919 uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx)2920 {2921 AssertPtrReturn(pTransferCtx, 0);2922 return pTransferCtx->cTransfers;2923 }2924 2925 /**2926 * Registers a clipboard transfer with a transfer context, i.e. allocates a transfer ID.2927 *2928 * @return VBox status code.2929 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers2930 * is reached.2931 * @param pTransferCtx Transfer context to register transfer to.2932 * @param pTransfer Transfer to register. The context takes ownership of the transfer on success.2933 * @param pidTransfer Where to return the transfer ID on success. Optional.2934 */2935 int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID *pidTransfer)2936 {2937 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);2938 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);2939 /* pidTransfer is optional. */2940 2941 /*2942 * Pick a random bit as starting point. If it's in use, search forward2943 * for a free one, wrapping around. We've reserved both the zero'th and2944 * max-1 IDs.2945 */2946 SHCLTRANSFERID idTransfer = RTRandU32Ex(1, VBOX_SHCL_MAX_TRANSFERS - 2);2947 2948 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer))2949 { /* likely */ }2950 else if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */)2951 {2952 /* Forward search. */2953 int iHit = ASMBitNextClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS, idTransfer);2954 if (iHit < 0)2955 iHit = ASMBitFirstClear(&pTransferCtx->bmTransferIds[0], VBOX_SHCL_MAX_TRANSFERS);2956 AssertLogRelMsgReturn(iHit >= 0, ("Transfer count: %RU16\n", pTransferCtx->cTransfers), VERR_SHCLPB_MAX_TRANSFERS_REACHED);2957 idTransfer = iHit;2958 AssertLogRelMsgReturn(!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer), ("idObject=%#x\n", idTransfer), VERR_INTERNAL_ERROR_2);2959 }2960 else2961 {2962 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers));2963 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;2964 }2965 2966 Log2Func(("pTransfer=%p, idTransfer=%RU32 (%RU16 transfers)\n", pTransfer, idTransfer, pTransferCtx->cTransfers));2967 2968 pTransfer->State.uID = idTransfer;2969 2970 RTListAppend(&pTransferCtx->List, &pTransfer->Node);2971 2972 pTransferCtx->cTransfers++;2973 2974 if (pTransfer->Callbacks.pfnOnRegistered)2975 pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx);2976 2977 if (pidTransfer)2978 *pidTransfer = idTransfer;2979 2980 LogFlowFuncLeaveRC(VINF_SUCCESS);2981 return VINF_SUCCESS;2982 }2983 2984 /**2985 * Registers a clipboard transfer with a transfer context by specifying an ID for the transfer.2986 *2987 * @return VBox status code.2988 * @retval VERR_ALREADY_EXISTS if a transfer with the given ID already exists.2989 * @retval VERR_SHCLPB_MAX_TRANSFERS_REACHED if the maximum of concurrent transfers for this context has been reached.2990 * @param pTransferCtx Transfer context to register transfer to.2991 * @param pTransfer Transfer to register.2992 * @param idTransfer Transfer ID to use for registration.2993 */2994 int ShClTransferCtxTransferRegisterById(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID idTransfer)2995 {2996 LogFlowFunc(("cTransfers=%RU16, idTransfer=%RU32\n", pTransferCtx->cTransfers, idTransfer));2997 2998 if (pTransferCtx->cTransfers < VBOX_SHCL_MAX_TRANSFERS - 2 /* First and last are not used */)2999 {3000 if (!ASMBitTestAndSet(&pTransferCtx->bmTransferIds[0], idTransfer))3001 {3002 RTListAppend(&pTransferCtx->List, &pTransfer->Node);3003 3004 pTransfer->State.uID = idTransfer;3005 3006 if (pTransfer->Callbacks.pfnOnRegistered)3007 pTransfer->Callbacks.pfnOnRegistered(&pTransfer->CallbackCtx, pTransferCtx);3008 3009 pTransferCtx->cTransfers++;3010 return VINF_SUCCESS;3011 }3012 3013 return VERR_ALREADY_EXISTS;3014 }3015 3016 LogFunc(("Maximum number of transfers reached (%RU16 transfers)\n", pTransferCtx->cTransfers));3017 return VERR_SHCLPB_MAX_TRANSFERS_REACHED;3018 }3019 3020 /**3021 * Removes and unregisters a transfer from a transfer context.3022 *3023 * @param pTransferCtx Transfer context to remove transfer from.3024 * @param pTransfer Transfer to remove.3025 */3026 static void shclTransferCtxTransferRemoveAndUnregister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer)3027 {3028 RTListNodeRemove(&pTransfer->Node);3029 3030 Assert(pTransferCtx->cTransfers);3031 pTransferCtx->cTransfers--;3032 3033 Assert(pTransferCtx->cTransfers >= pTransferCtx->cRunning);3034 3035 if (pTransfer->Callbacks.pfnOnUnregistered)3036 pTransfer->Callbacks.pfnOnUnregistered(&pTransfer->CallbackCtx, pTransferCtx);3037 3038 LogFlowFunc(("Now %RU32 transfers left\n", pTransferCtx->cTransfers));3039 }3040 3041 /**3042 * Unregisters a transfer from an transfer context.3043 *3044 * @retval VINF_SUCCESS on success.3045 * @retval VERR_NOT_FOUND if the transfer ID was not found.3046 * @param pTransferCtx Transfer context to unregister transfer from.3047 * @param idTransfer Transfer ID to unregister.3048 */3049 int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)3050 {3051 int rc = VINF_SUCCESS;3052 AssertMsgStmt(ASMBitTestAndClear(&pTransferCtx->bmTransferIds, idTransfer), ("idTransfer=%#x\n", idTransfer), rc = VERR_NOT_FOUND);3053 3054 LogFlowFunc(("idTransfer=%RU32\n", idTransfer));3055 3056 PSHCLTRANSFER pTransfer = shClTransferCtxGetTransferByIdInternal(pTransferCtx, idTransfer);3057 if (pTransfer)3058 {3059 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer);3060 }3061 else3062 rc = VERR_NOT_FOUND;3063 3064 LogFlowFuncLeaveRC(rc);3065 return rc;3066 }3067 3068 /**3069 * Cleans up all associated transfers which are not needed (anymore).3070 * This can be due to transfers which only have been announced but not / never being run.3071 *3072 * @param pTransferCtx Transfer context to cleanup transfers for.3073 */3074 void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx)3075 {3076 AssertPtrReturnVoid(pTransferCtx);3077 3078 LogFlowFunc(("pTransferCtx=%p, cTransfers=%RU16 cRunning=%RU16\n",3079 pTransferCtx, pTransferCtx->cTransfers, pTransferCtx->cRunning));3080 3081 if (pTransferCtx->cTransfers == 0)3082 return;3083 3084 /* Remove all transfers which are not in a running state (e.g. only announced). */3085 PSHCLTRANSFER pTransfer, pTransferNext;3086 RTListForEachSafe(&pTransferCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)3087 {3088 if (ShClTransferGetStatus(pTransfer) != SHCLTRANSFERSTATUS_STARTED)3089 {3090 shclTransferCtxTransferRemoveAndUnregister(pTransferCtx, pTransfer);3091 3092 ShClTransferDestroy(pTransfer);3093 3094 RTMemFree(pTransfer);3095 pTransfer = NULL;3096 }3097 }3098 }3099 3100 /**3101 * Returns whether the maximum of concurrent transfers of a specific transfer contexthas been reached or not.3102 *3103 * @returns \c if maximum has been reached, \c false if not.3104 * @param pTransferCtx Transfer context to determine value for.3105 */3106 bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx)3107 {3108 AssertPtrReturn(pTransferCtx, true);3109 3110 LogFlowFunc(("cRunning=%RU32, cMaxRunning=%RU32\n", pTransferCtx->cRunning, pTransferCtx->cMaxRunning));3111 3112 Assert(pTransferCtx->cRunning <= pTransferCtx->cMaxRunning);3113 return pTransferCtx->cRunning == pTransferCtx->cMaxRunning;3114 }3115 3116 /**3117 * Copies file system objinfo from IPRT to Shared Clipboard format.3118 *3119 * @param pDst The Shared Clipboard structure to convert data to.3120 * @param pSrc The IPRT structure to convert data from.3121 */3122 void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc)3123 {3124 pDst->cbObject = pSrc->cbObject;3125 pDst->cbAllocated = pSrc->cbAllocated;3126 pDst->AccessTime = pSrc->AccessTime;3127 pDst->ModificationTime = pSrc->ModificationTime;3128 pDst->ChangeTime = pSrc->ChangeTime;3129 pDst->BirthTime = pSrc->BirthTime;3130 pDst->Attr.fMode = pSrc->Attr.fMode;3131 /* Clear bits which we don't pass through for security reasons. */3132 pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);3133 RT_ZERO(pDst->Attr.u);3134 switch (pSrc->Attr.enmAdditional)3135 {3136 default:3137 case RTFSOBJATTRADD_NOTHING:3138 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_NOTHING;3139 break;3140 3141 case RTFSOBJATTRADD_UNIX:3142 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_UNIX;3143 pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid;3144 pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid;3145 pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks;3146 pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice;3147 pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId;3148 pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags;3149 pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId;3150 pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device;3151 break;3152 3153 case RTFSOBJATTRADD_EASIZE:3154 pDst->Attr.enmAdditional = SHCLFSOBJATTRADD_EASIZE;3155 pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb;3156 break;3157 }3158 }3159 3160 /**3161 * Converts Shared Clipboard create flags (see SharedClipboard-transfers.h) into IPRT create flags.3162 *3163 * @returns IPRT status code.3164 * @param fShClFlags Shared clipboard create flags.3165 * @param[out] pfOpen Where to store the RTFILE_O_XXX flags for3166 * RTFileOpen.3167 *3168 * @sa Initially taken from vbsfConvertFileOpenFlags().3169 */3170 static int shClConvertFileCreateFlags(uint32_t fShClFlags, uint64_t *pfOpen)3171 {3172 AssertMsgReturnStmt(!(fShClFlags & ~SHCL_OBJ_CF_VALID_MASK), ("%#x4\n", fShClFlags), *pfOpen = 0, VERR_INVALID_FLAGS);3173 3174 uint64_t fOpen = 0;3175 3176 switch (fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_RW)3177 {3178 case SHCL_OBJ_CF_ACCESS_NONE:3179 {3180 #ifdef RT_OS_WINDOWS3181 if ((fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_ATTR) != SHCL_OBJ_CF_ACCESS_ATTR_NONE)3182 fOpen |= RTFILE_O_OPEN | RTFILE_O_ATTR_ONLY;3183 else3184 #endif3185 fOpen |= RTFILE_O_OPEN | RTFILE_O_READ;3186 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_NONE\n"));3187 break;3188 }3189 3190 case SHCL_OBJ_CF_ACCESS_READ:3191 {3192 fOpen |= RTFILE_O_OPEN | RTFILE_O_READ;3193 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_READ\n"));3194 break;3195 }3196 3197 default:3198 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);3199 }3200 3201 switch (fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_ATTR)3202 {3203 case SHCL_OBJ_CF_ACCESS_ATTR_NONE:3204 {3205 fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;3206 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_NONE\n"));3207 break;3208 }3209 3210 case SHCL_OBJ_CF_ACCESS_ATTR_READ:3211 {3212 fOpen |= RTFILE_O_ACCESS_ATTR_READ;3213 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_ATTR_READ\n"));3214 break;3215 }3216 3217 default:3218 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);3219 }3220 3221 /* Sharing mask */3222 switch (fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_DENY)3223 {3224 case SHCL_OBJ_CF_ACCESS_DENYNONE:3225 fOpen |= RTFILE_O_DENY_NONE;3226 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYNONE\n"));3227 break;3228 3229 case SHCL_OBJ_CF_ACCESS_DENYWRITE:3230 fOpen |= RTFILE_O_DENY_WRITE;3231 LogFlowFunc(("SHCL_OBJ_CF_ACCESS_DENYWRITE\n"));3232 break;3233 3234 default:3235 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);3236 }3237 3238 *pfOpen = fOpen;3239 3240 LogFlowFuncLeaveRC(VINF_SUCCESS);3241 return VINF_SUCCESS;3242 }3243 3244 /**3245 * Translates a clipboard transfer status (SHCLTRANSFERSTATUS_XXX) into a string.3246 *3247 * @returns Transfer status string name.3248 * @param enmStatus The transfer status to translate.3249 */3250 const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus)3251 {3252 switch (enmStatus)3253 {3254 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_NONE);3255 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_INITIALIZED);3256 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STARTED);3257 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_STOPPED);3258 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_CANCELED);3259 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_KILLED);3260 RT_CASE_RET_STR(SHCLTRANSFERSTATUS_ERROR);3261 }3262 return "Unknown";3263 }3264
Note:
See TracChangeset
for help on using the changeset viewer.