VirtualBox

Ignore:
Timestamp:
May 4, 2015 12:38:57 PM (10 years ago)
Author:
vboxsync
Message:

DnD:

  • Overhauled "dropped files" directory + general file handling: Keep the directories/files open when doing the actual transfers (only protocol >= 2)
  • Unified "dropped files" directory creation/rollback handling for guest/host parts.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r55571 r55640  
    372372    void *pvTmpData = RTMemAlloc(cbTmpData);
    373373    if (!pvTmpData)
    374         rc = VERR_NO_MEMORY;
    375 
    376     /* Create and query the (unique) drop target directory. */
     374        return VERR_NO_MEMORY;
     375
     376    /* Create and query the (unique) drop target directory in the user's temporary directory. */
     377    DNDDIRDROPPEDFILES dirDroppedFiles;
     378    const char *pszDropDir;
     379    rc = DnDDirDroppedFilesCreateAndOpenTemp(&dirDroppedFiles);
     380    if (RT_SUCCESS(rc))
     381        pszDropDir = DnDDirDroppedFilesGetDirAbs(&dirDroppedFiles);
     382
    377383    DnDURIList lstURI;
    378     char szDropDir[RTPATH_MAX];
    379     if (RT_SUCCESS(rc))
    380         rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
    381 
    382     if (RT_FAILURE(rc))
    383     {
    384         int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
    385         AssertRC(rc2);
    386 
    387         if (pvTmpData)
    388             RTMemFree(pvTmpData);
    389         return rc;
    390     }
    391 
    392     /* Lists for holding created files & directories in the case of a rollback. */
    393     RTCList<RTCString> guestDirList;
    394     RTCList<RTCString> guestFileList;
    395 
    396384    DnDURIObject objFile(DnDURIObject::File);
    397385
     
    405393        uint32_t uNextMsg;
    406394        uint32_t cNextParms;
    407         LogFlowFunc(("Waiting for new message ...\n"));
    408395        rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
    409396        if (RT_SUCCESS(rc))
     
    423410                                 szPathName, cbPathName, fMode, rc));
    424411
    425                     /*
    426                      * Important: HOST_DND_HG_SND_DIR sends the path (directory) name without URI specifications, that is,
    427                      *            only the pure name! To match the accounting though we have to translate the pure name into
    428                      *            a valid URI again.
    429                      *
    430                      ** @todo     Fix this URI translation!
    431                      */
    432                     RTCString strPath(szPathName);
    433                     if (RT_SUCCESS(rc))
    434                         rc = objFile.RebaseURIPath(strPath);
    435                     if (RT_SUCCESS(rc))
     412                    char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
     413                    if (pszPathAbs)
    436414                    {
    437                         rc = DnDPathSanitize(szPathName, sizeof(szPathName));
    438                         char *pszNewDir = RTPathJoinA(szDropDir, szPathName);
    439                         if (pszNewDir)
     415                        rc = RTDirCreate(pszPathAbs, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
     416                        if (RT_SUCCESS(rc))
     417                            rc = DnDDirDroppedAddDir(&dirDroppedFiles, pszPathAbs);
     418
     419                        RTStrFree(pszPathAbs);
     420                    }
     421                    else
     422                        rc = VERR_NO_MEMORY;
     423                    break;
     424                }
     425                case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
     426                case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     427                {
     428                    if (uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR)
     429                        rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
     430                                                                  szPathName,
     431                                                                  sizeof(szPathName),
     432                                                                  &fFlags,
     433                                                                  &fMode,
     434                                                                  &cbDataToRead);
     435                    else
     436                        rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
     437                                                               szPathName,
     438                                                               sizeof(szPathName),
     439                                                               &cbPathName,
     440                                                               pvTmpData,
     441                                                               cbTmpData,
     442                                                               &cbDataRecv,
     443                                                               &fMode);
     444                    if (   RT_SUCCESS(rc)
     445                        && (   uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR
     446                             /* Protocol v1 always sends the file name, so try opening every time. */
     447                            || pCtx->uProtocol <= 1)
     448                       )
     449                    {
     450                        char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
     451                        if (pszPathAbs)
    440452                        {
    441                             rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
    442                             RTStrFree(pszNewDir);
     453                            LogFlowFunc(("Opening pszPathName=%s, cbPathName=%RU32, fMode=0x%x, cbSize=%RU64\n",
     454                                         szPathName, cbPathName, fMode, cbDataToRead));
     455
     456                            uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
     457                            if (pCtx->uProtocol <= 1)
     458                                fOpen |= RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND;
     459                            else
     460                                fOpen |= RTFILE_O_CREATE_REPLACE;
     461
     462                            /* Is there already a file open, e.g. in transfer? */
     463                            if (!objFile.IsOpen())
     464                            {
     465
     466                                RTCString strPathAbs(pszPathAbs);
     467                                rc = objFile.OpenEx(strPathAbs, DnDURIObject::File, DnDURIObject::Target, fOpen,
     468                                                    (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
     469                                if (RT_SUCCESS(rc))
     470                                {
     471                                    rc = DnDDirDroppedAddFile(&dirDroppedFiles, strPathAbs.c_str());
     472                                    if (RT_SUCCESS(rc))
     473                                    {
     474                                        cbDataWritten = 0;
     475
     476                                        if (pCtx->uProtocol >= 2) /* Set the expected file size. */
     477                                            objFile.SetSize(cbDataToRead);
     478                                    }
     479                                }
     480                            }
     481                            else
     482                                rc = VERR_WRONG_ORDER;
     483
     484                            RTStrFree(pszPathAbs);
    443485                        }
    444486                        else
    445487                            rc = VERR_NO_MEMORY;
    446 
     488                    }
     489
     490                    if (   RT_SUCCESS(rc)
     491                        && uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA)
     492                    {
     493                        bool fClose = false;
     494
     495                        uint32_t cbWritten;
     496                        rc = objFile.Write(pvTmpData, cbDataRecv, &cbWritten);
    447497                        if (RT_SUCCESS(rc))
    448498                        {
    449                             if (!guestDirList.contains(strPath))
    450                                 guestDirList.append(strPath);
    451                         }
    452                     }
    453                     break;
    454                 }
    455                 case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
    456                 {
    457                     rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
    458                                                               szPathName,
    459                                                               sizeof(szPathName),
    460                                                               &fFlags,
    461                                                               &fMode,
    462                                                               &cbDataToRead);
    463                     LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR pszPathName=%s, fFlags=0x%x, fMode=0x%x, cbDataToRead=%RU64, rc=%Rrc\n",
    464                                  szPathName, fFlags, fMode, cbDataToRead, rc));
    465 
    466                     cbDataWritten = 0;
    467                     break;
    468                 }
    469                 case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
    470                 {
    471                     rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
    472                                                            szPathName,
    473                                                            sizeof(szPathName),
    474                                                            &cbPathName,
    475                                                            pvTmpData,
    476                                                            cbTmpData,
    477                                                            &cbDataRecv,
    478                                                            &fMode);
    479                     LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA pszPathName=%s, cbPathName=%RU32, pvData=0x%p, cbDataRecv=%RU32, fMode=0x%x, rc=%Rrc\n",
    480                                  szPathName, cbPathName, pvTmpData, cbDataRecv, fMode, rc));
    481 
    482                     /*
    483                      * Important: HOST_DND_HG_SND_FILE sends the path (directory) name without URI specifications, that is,
    484                      *            only the pure name! To match the accounting though we have to translate the pure name into
    485                      *            a valid URI again.
    486                      *
    487                      ** @todo     Fix this URI translation!
    488                      */
    489                     RTCString strPath(szPathName);
    490                     if (RT_SUCCESS(rc))
    491                         rc = objFile.RebaseURIPath(strPath);
    492                     if (RT_SUCCESS(rc))
    493                     {
    494                         rc = DnDPathSanitize(szPathName, sizeof(szPathName));
    495                         if (RT_SUCCESS(rc))
    496                         {
    497                             char *pszPathAbs = RTPathJoinA(szDropDir, szPathName);
    498                             if (pszPathAbs)
     499                            if (pCtx->uProtocol >= 2)
    499500                            {
    500                                 RTFILE hFile;
    501                                 /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will
    502                                  *               create all sorts of funny races because we don't know if the guest has
    503                                  *               modified the file in between the file data send calls.
    504                                  *
    505                                  *               See HOST_DND_HG_SND_FILE_HDR for a good place to do this. */
    506                                 rc = RTFileOpen(&hFile, pszPathAbs,
    507                                                 RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
    508                                 if (RT_SUCCESS(rc))
    509                                 {
    510                                     /** @todo r=andy Not very safe to assume that we were last appending to the current file. */
    511                                     rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
    512                                     if (RT_SUCCESS(rc))
    513                                     {
    514                                         rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
    515                                         if (RT_SUCCESS(rc))
    516                                         {
    517                                             if (fMode & RTFS_UNIX_MASK) /* Valid UNIX mode? */
    518                                                 rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
    519 
    520                                             cbDataWritten += cbDataRecv;
    521                                             Assert(cbDataWritten <= cbDataToRead);
    522                                         }
    523                                     }
    524 
    525                                     RTFileClose(hFile);
    526 
    527                                     if (!guestFileList.contains(pszPathAbs)) /* Add the file to (rollback) list. */
    528                                         guestFileList.append(pszPathAbs);
    529                                 }
    530                                 else
    531                                     LogFlowFunc(("Opening file failed with rc=%Rrc\n", rc));
    532 
    533                                 RTStrFree(pszPathAbs);
     501                                /* Data transfer complete? Close the file. */
     502                                fClose = objFile.IsComplete();
    534503                            }
    535504                            else
    536                                 rc = VERR_NO_MEMORY;
     505                                fClose = true; /* Always close the file after each chunk. */
     506
     507                            cbDataWritten += cbWritten;
     508                            Assert(cbDataWritten <= cbDataToRead);
     509                        }
     510
     511                        if (fClose)
     512                        {
     513                            LogFlowFunc(("Closing file\n"));
     514                            objFile.Close();
    537515                        }
    538516                    }
     
    607585#endif
    608586        }
    609         else
    610         {
    611             /* All URI data processed? */
    612             if (rc == VERR_NO_DATA)
    613                 rc = VINF_SUCCESS;
    614             break;
    615         }
    616587
    617588        if (RT_FAILURE(rc))
     
    622593    LogFlowFunc(("Loop ended with %Rrc\n", rc));
    623594
     595    /* All URI data processed? */
     596    if (rc == VERR_NO_DATA)
     597        rc = VINF_SUCCESS;
     598
    624599    if (pvTmpData)
    625600        RTMemFree(pvTmpData);
    626601
    627     /* Cleanup on failure or if the user has canceled the operation. */
     602    /* Cleanup on failure or if the user has canceled the operation or
     603     * something else went wrong. */
    628604    if (RT_FAILURE(rc))
    629605    {
    630         LogFlowFunc(("Rolling back ...\n"));
    631 
    632         /* Rollback by removing any stuff created. */
    633         for (size_t i = 0; i < guestFileList.size(); ++i)
    634             RTFileDelete(guestFileList.at(i).c_str());
    635         for (size_t i = 0; i < guestDirList.size(); ++i)
    636             RTDirRemove(guestDirList.at(i).c_str());
     606        int rc2 = DnDDirDroppedFilesRollback(&dirDroppedFiles);
     607        AssertRC(rc2); /* Not fatal, don't report back to host. */
    637608    }
    638609    else
     
    647618            RTMemFree(pvData);
    648619
    649             RTCString strData = lstURI.RootToString(szDropDir);
     620            RTCString strData = lstURI.RootToString(pszDropDir);
    650621            LogFlowFunc(("cbDataToRead: %zu -> %zu\n", cbDataToRead, strData.length() + 1));
    651622
     
    663634    }
    664635
    665     /* Try removing the (empty) drop directory in any case. */
    666     int rc2 = RTDirRemove(szDropDir);
    667     if (RT_FAILURE(rc2))
    668         LogFunc(("Warning: Unable to remove drop directory \"%s\": %Rrc\n", szDropDir, rc2));
     636    /*
     637     * Close the dropped files directory.
     638     * Don't try to remove it here, however, as the files are being needed
     639     * by the client's drag'n drop operation lateron.
     640     */
     641    int rc2 = DnDDirDroppedFilesClose(&dirDroppedFiles, false);
     642    if (RT_FAILURE(rc2)) /* Not fatal, don't report back to host. */
     643        LogFlowFunc(("Closing dropped files directory failed with %Rrc\n", rc2));
    669644
    670645    LogFlowFuncLeaveRC(rc);
     
    872847        AssertPtr(pcbFormatRecv);
    873848        if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
     849        {
    874850            rc = vbglR3DnDHGProcessURIMessages(pCtx,
    875851                                               puScreenId,
     
    880856                                               cbData,
    881857                                               pcbDataRecv);
     858        }
    882859        else
    883860            rc = VERR_NOT_SUPPORTED;
     861
     862        if (RT_FAILURE(rc))
     863        {
     864            if (RT_FAILURE(rc))
     865            {
     866                int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
     867                AssertRC(rc2);
     868            }
     869        }
    884870    }
    885871
Note: See TracChangeset for help on using the changeset viewer.

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