VirtualBox

Ignore:
Timestamp:
May 24, 2023 10:37:12 AM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
157609
Message:

Shared Clipboard: Moved code for handling local filesystems with transfers into an own provider interface implementation. This cleans up the generic code a lot. bugref:9437

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  
    4747static PSHCLTRANSFER shClTransferCtxGetTransferByIdInternal(PSHCLTRANSFERCTX pTransferCtx, uint32_t uId);
    4848static 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
    5450
    5551/**
     
    578574    }
    579575
    580     int rc = shClTransferValidatePath(pszName, false /* fMustExist */);
     576    int rc = ShClTransferValidatePath(pszName, false /* fMustExist */);
    581577    if (RT_FAILURE(rc))
    582578        return false;
     
    840836 * @param   hObj                Object handle of the object to get handle info for.
    841837 */
    842 DECLINLINE(PSHCLOBJHANDLEINFO) shClTransferObjGet(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj)
     838PSHCLOBJHANDLEINFO ShClTransferObjGet(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj)
    843839{
    844840    PSHCLOBJHANDLEINFO pIt;
     
    874870
    875871    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);
    929874    else
    930         AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
     875        rc = VERR_NOT_SUPPORTED;
    931876
    932877    LogFlowFuncLeaveRC(rc);
     
    945890    AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
    946891
    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);
    1011895    else
    1012         AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
     896        rc = VERR_NOT_SUPPORTED;
    1013897
    1014898    LogFlowFuncLeaveRC(rc);
     
    1036920    /** @todo Validate fFlags. */
    1037921
    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);
    1076925    else
    1077         AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
     926        rc = VERR_NOT_SUPPORTED;
    1078927
    1079928    LogFlowFuncLeaveRC(rc);
     
    1100949    /* pcbWritten is optional. */
    1101950
    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);
    1134954    else
    1135         AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
     955        rc = VERR_NOT_SUPPORTED;
    1136956
    1137957    LogFlowFuncLeaveRC(rc);
     
    13761196
    13771197/**
     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 */
     1205int 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 */
     1232int 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 */
     1257int 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/**
    13781276 * Returns a specific list handle info of a clipboard transfer.
    13791277 *
     
    13821280 * @param   hList               List handle of the list to get handle info for.
    13831281 */
    1384 DECLINLINE(PSHCLLISTHANDLEINFO) shClTransferListGetByHandle(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)
     1282PSHCLLISTHANDLEINFO ShClTransferListGetByHandle(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList)
    13851283{
    13861284    PSHCLLISTHANDLEINFO pIt;
     
    13951293
    13961294/**
    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 */
     1304PSHCLTRANSFEROBJ 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 */
     1324int 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
     1342int 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 */
     1365bool 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 */
     1390void 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 */
     1425void 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 */
     1441int 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 */
     1464static 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 */
     1493void 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 */
     1528uint32_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 */
     1543DECLINLINE(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 */
     1563int 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 */
     1627int 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 */
     1653int 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 */
     1768int 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 */
     1787SHCLTRANSFERID 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 */
     1800SHCLTRANSFERDIR 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 */
     1816int 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 */
     1829SHCLSOURCE 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 */
     1843SHCLTRANSFERSTATUS 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 */
     1859int 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 */
     1881int 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 */
     1918static 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 */
     1958static 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 */
     1984int 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 */
     2012void 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 */
     2042void 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 */
     2064static 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 */
     2083static 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 */
     2105PSHCLTRANSFER 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 */
     2117PSHCLTRANSFER 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 */
     2128uint32_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 */
     2140uint32_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 */
     2156int 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 */
     2215int 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 */
     2247static 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 */
     2270int 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 */
     2295void 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 */
     2327bool 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 */
     2343void 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 */
     2387const 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";
    14052400}
    14062401
     
    14122407 * @param   fMustExist          Whether the path to validate also must exist.
    14132408 */
    1414 static int shClTransferValidatePath(const char *pcszPath, bool fMustExist)
     2409int ShClTransferValidatePath(const char *pcszPath, bool fMustExist)
    14152410{
    14162411    int rc = VINF_SUCCESS;
     
    14632458}
    14642459
    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         else
    1517             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 pInfo
    1552             = (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                             else
    1575                                 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                             else
    1589                                 LogRel(("Shared Clipboard: Opening file '%s' failed with %Rrc\n", pInfo->pszPathLocalAbs, rc));
    1590                         }
    1591                         else
    1592                             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                         else
    1608                         {
    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         else
    1633             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         else
    1642             rc = VERR_NOT_SUPPORTED;
    1643     }
    1644     else
    1645         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         else
    1697             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         else
    1706             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                 do
    1763                 {
    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                             else
    1793                                 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         else
    1820             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         else
    1887             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         else
    1896             rc = VERR_NOT_SUPPORTED;
    1897     }
    1898     else
    1899         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                         else
    2048                             rc = VERR_NO_MEMORY;
    2049                     }
    2050 
    2051                     break;
    2052                 }
    2053 
    2054                 default:
    2055                     rc = VERR_NOT_SUPPORTED;
    2056                     break;
    2057             }
    2058         }
    2059         else
    2060             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         else
    2067             rc = VERR_NOT_SUPPORTED;
    2068     }
    2069     else
    2070         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 0
    2084     if (pTransfer->ProviderIface.pfnListEntryWrite)
    2085         rc = pTransfer->ProviderIface.pfnListEntryWrite(&pTransfer->ProviderCtx, hList, pEntry);
    2086 #endif
    2087 
    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     else
    2112         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, the
    2122  *                              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_pfnCallback
    2134 
    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_CALLBACK
    2143 
    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                 else
    2343                     rc = VERR_NO_MEMORY;
    2344             }
    2345         }
    2346     }
    2347     else
    2348         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 paRootListEntries
    2383                 = (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             else
    2397                 rc = VERR_NO_MEMORY;
    2398         }
    2399         else
    2400             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         else
    2414             rc = VERR_NOT_SUPPORTED;
    2415     }
    2416     else
    2417         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                 else
    2473                     rc = VERR_INVALID_PARAMETER;
    2474             }
    2475             else
    2476                 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     else
    2529     {
    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     else
    2678         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         else
    2723             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_HTTP
    2832     /** @todo Anything to do here? */
    2833 #endif
    2834 }
    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 transfers
    2930  *          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 forward
    2943      * for a free one, wrapping around.  We've reserved both the zero'th and
    2944      * 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     else
    2961     {
    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     else
    3062         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 for
    3166  *                          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_WINDOWS
    3181             if ((fShClFlags & SHCL_OBJ_CF_ACCESS_MASK_ATTR) != SHCL_OBJ_CF_ACCESS_ATTR_NONE)
    3182                 fOpen |= RTFILE_O_OPEN | RTFILE_O_ATTR_ONLY;
    3183             else
    3184 #endif
    3185                 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.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette