VirtualBox

Changeset 97395 in vbox for trunk/src/VBox/Main/src-client


Ignore:
Timestamp:
Nov 4, 2022 11:17:21 AM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
154395
Message:

Guest Control/Main: Rewrite of the path building and directory walking code for the copyFrom / copyTo guest session tasks, to (hopefully) have a cleaner structure. The new path building now also takes into account whether a destination has a trailing delimiter and then act accordingly (see rules in GuestPath::BuildDestinationPath()). Adjusted VBoxManage and FE/Qt to also reflect that; should now work as common tools like cp. Added new test cases and also re-enabled old ones which were disabled since quite a while (should pass now). ​bugref:10286

Location:
trunk/src/VBox/Main/src-client
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r97304 r97395  
    14181418}
    14191419
     1420/**
     1421 * Converts a PathStyle_T to a human-readable string.
     1422 *
     1423 * @returns Human-readable string of PathStyle_T.
     1424 * @param   enmPathStyle        PathStyle_T to convert.
     1425 */
     1426/* static */
     1427const char *GuestBase::pathStyleToStr(PathStyle_T enmPathStyle)
     1428{
     1429    switch (enmPathStyle)
     1430    {
     1431        case PathStyle_DOS:     return "DOS";
     1432        case PathStyle_UNIX:    return "UNIX";
     1433        case PathStyle_Unknown: return "Unknown";
     1434        default:                break;
     1435    }
     1436
     1437    return "<invalid>";
     1438}
     1439
    14201440GuestObject::GuestObject(void)
    14211441    : mSession(NULL),
     
    16901710
    16911711/**
     1712 * Builds a (final) destination path from a given source + destination path.
     1713 *
     1714 * This does not utilize any file system access whatsoever. Used for guest and host paths.
     1715 *
     1716 * @returns VBox status code.
     1717 * @param   strSrcPath          Source path to build destination path for.
     1718 * @param   enmSrcPathStyle     Path style the source path is in.
     1719 * @param   strDstPath          Destination path to use for building the (final) destination path.
     1720 * @param   enmDstPathStyle     Path style the destination path is in.
     1721 *
     1722 * @note    See rules within the function.
     1723 */
     1724/* static */
     1725int GuestPath::BuildDestinationPath(const Utf8Str &strSrcPath, PathStyle_T enmSrcPathStyle, Utf8Str &strDstPath, PathStyle_T enmDstPathStyle)
     1726{
     1727    /**
     1728     * Rules:
     1729     *
     1730     * #    source       dest             final dest                        remarks
     1731     *
     1732     * 1    /gst/dir1/   /dst/dir2/       /dst/dir2/<contents of dir1>      Just copies contents of <contents>, not the directory itself.
     1733     * 2    /gst/dir1    /dst/dir2/       /dst/dir2/dir1                    Copies dir1 into dir2.
     1734     * 3    /gst/dir1    /dst/dir2        /dst/dir2                         Overwrites stuff from dir2 with stuff from dir1.
     1735     */
     1736    const char *pszSrcName = RTPathFilenameEx(strSrcPath.c_str(),
     1737                                                 enmSrcPathStyle == PathStyle_DOS
     1738                                              ? RTPATH_STR_F_STYLE_DOS : RTPATH_STR_F_STYLE_UNIX);
     1739
     1740    const char *pszDstName = RTPathFilenameEx(strDstPath.c_str(),
     1741                                                enmDstPathStyle == PathStyle_DOS
     1742                                              ? RTPATH_STR_F_STYLE_DOS : RTPATH_STR_F_STYLE_UNIX);
     1743
     1744    if (   (!pszSrcName && !pszDstName)  /* #1 */
     1745        || ( pszSrcName &&  pszDstName)) /* #3 */
     1746    {
     1747        /* Note: Must have DirectoryFlag_CopyIntoExisting + FileFlag_NoReplace *not* set. */
     1748    }
     1749    else if (pszSrcName && !pszDstName) /* #2 */
     1750    {
     1751        strDstPath += RTPATH_SLASH_STR;
     1752        strDstPath += pszSrcName;
     1753    }
     1754
     1755    return VINF_SUCCESS;
     1756}
     1757
     1758/**
    16921759 * Translates a path from a specific path style into another.
    16931760 *
     
    17101777    AssertReturn(RTStrIsValidEncoding(strPath.c_str()), VERR_INVALID_PARAMETER);
    17111778
    1712 #ifdef DEBUG
    1713     Utf8Str const strPathOrg = strPath; /* Make a backup so that we later can log stuff properly. */
    1714 #endif
    1715 
    17161779    int vrc = VINF_SUCCESS;
    17171780
     
    17221785        || (fForce && enmDstPathStyle == PathStyle_UNIX))
    17231786    {
    1724         strTranslated = RTPathChangeToUnixSlashes(strPath.mutableRaw(), true /* fForce */);
     1787        strTranslated = strPath;
     1788        RTPathChangeToUnixSlashes(strTranslated.mutableRaw(), true /* fForce */);
    17251789    }
    17261790    else if (enmDstPathStyle == PathStyle_DOS)
     
    17291793            && fForce)
    17301794        {
    1731             strTranslated = RTPathChangeToDosSlashes(strPath.mutableRaw(), true /* fForce */);
     1795            strTranslated = strPath;
     1796            RTPathChangeToDosSlashes(strTranslated.mutableRaw(), true /* fForce */);
    17321797        }
    17331798        else if (enmSrcPathStyle == PathStyle_UNIX)
     
    17781843
    17791844    if (RT_FAILURE(vrc))
     1845    {
     1846        LogRel2(("Guest Control: Translating path '%s' -> '%s' failed, vrc=%Rrc\n", strPath.c_str(), strTranslated.c_str(), vrc));
    17801847        return vrc;
     1848    }
    17811849
    17821850    /* Cleanup. */
     
    18081876    strTranslated.jolt();
    18091877
     1878    LogRel2(("Guest Control: Translating '%s' (%s) -> '%s' (%s)\n",
     1879             strPath.c_str(), GuestBase::pathStyleToStr(enmSrcPathStyle),
     1880             strTranslated.c_str(), GuestBase::pathStyleToStr(enmDstPathStyle), vrc));
     1881
    18101882    if (RT_SUCCESS(vrc))
    18111883        strPath = strTranslated;
    18121884
    1813 #ifdef DEBUG
    1814     LogRel2(("Guest Control: Mapping '%s' -> '%s', vrc=%Rrc\n", strPathOrg.c_str(), strPath.c_str(), vrc));
    1815 #endif
    18161885    return vrc;
    18171886}
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r97305 r97395  
    887887 * @return COM status, error set on failure
    888888 * @param  strFlags             String to extract flags from.
     889 * @param  fStrict              Whether to set an error when an unknown / invalid flag is detected.
    889890 * @param  pfFlags              Where to store the extracted (and validated) flags.
    890891 */
    891 HRESULT GuestSession::i_directoryCopyFlagFromStr(const com::Utf8Str &strFlags, DirectoryCopyFlag_T *pfFlags)
     892HRESULT GuestSession::i_directoryCopyFlagFromStr(const com::Utf8Str &strFlags, bool fStrict, DirectoryCopyFlag_T *pfFlags)
    892893{
    893894    unsigned fFlags = DirectoryCopyFlag_None;
     
    918919                else if (MATCH_KEYWORD("FollowLinks"))
    919920                    fFlags |= (unsigned)DirectoryCopyFlag_FollowLinks;
    920                 else
     921                else if (fStrict)
    921922                    return setError(E_INVALIDARG, tr("Invalid directory copy flag: %.*s"), (int)cchKeyword, pszNext);
    922923#undef MATCH_KEYWORD
     
    14581459 * @return COM status, error set on failure
    14591460 * @param  strFlags             String to extract flags from.
     1461 * @param  fStrict              Whether to set an error when an unknown / invalid flag is detected.
    14601462 * @param  pfFlags              Where to store the extracted (and validated) flags.
    14611463 */
    1462 HRESULT GuestSession::i_fileCopyFlagFromStr(const com::Utf8Str &strFlags, FileCopyFlag_T *pfFlags)
     1464HRESULT GuestSession::i_fileCopyFlagFromStr(const com::Utf8Str &strFlags, bool fStrict, FileCopyFlag_T *pfFlags)
    14631465{
    14641466    unsigned fFlags = (unsigned)FileCopyFlag_None;
     
    14891491                else if (MATCH_KEYWORD("Update"))
    14901492                    fFlags |= (unsigned)FileCopyFlag_Update;
    1491                 else
     1493                else if (fStrict)
    14921494                    return setError(E_INVALIDARG, tr("Invalid file copy flag: %.*s"), (int)cchKeyword, pszNext);
    14931495#undef MATCH_KEYWORD
     
    34613463
    34623464    GuestSessionFsSourceSpec source;
    3463     source.strSource            = aSource;
    3464     source.enmType              = FsObjType_File;
    3465     source.enmPathStyle         = i_getGuestPathStyle();
    3466     source.fDryRun              = false; /** @todo Implement support for a dry run. */
    3467     source.Type.File.fCopyFlags = (FileCopyFlag_T)fFlags;
     3465    source.strSource      = aSource;
     3466    source.enmType        = FsObjType_File;
     3467    source.enmPathStyle   = i_getGuestPathStyle();
     3468    source.fDryRun        = false; /** @todo Implement support for a dry run. */
     3469    source.fDirCopyFlags  = DirectoryCopyFlag_None;
     3470    source.fFileCopyFlags = (FileCopyFlag_T)fFlags;
    34683471
    34693472    SourceSet.push_back(source);
     
    34893492
    34903493    GuestSessionFsSourceSpec source;
    3491     source.strSource            = aSource;
    3492     source.enmType              = FsObjType_File;
    3493     source.enmPathStyle         = GuestSession::i_getHostPathStyle();
    3494     source.fDryRun              = false; /** @todo Implement support for a dry run. */
    3495     source.Type.File.fCopyFlags = (FileCopyFlag_T)fFlags;
     3494    source.strSource      = aSource;
     3495    source.enmType        = FsObjType_File;
     3496    source.enmPathStyle   = GuestSession::i_getHostPathStyle();
     3497    source.fDryRun        = false; /** @todo Implement support for a dry run. */
     3498    source.fDirCopyFlags  = DirectoryCopyFlag_None;
     3499    source.fFileCopyFlags = (FileCopyFlag_T)fFlags;
    34963500
    34973501    SourceSet.push_back(source);
     
    35583562        source.fDryRun      = false; /** @todo Implement support for a dry run. */
    35593563
    3560         HRESULT hrc;
    3561         if (source.enmType == FsObjType_Directory)
    3562         {
    3563             hrc = GuestSession::i_directoryCopyFlagFromStr(strFlags, &source.Type.Dir.fCopyFlags);
    3564         }
    3565         else if (source.enmType == FsObjType_File)
    3566             hrc = GuestSession::i_fileCopyFlagFromStr(strFlags, &source.Type.File.fCopyFlags);
    3567         else
    3568             return setError(E_INVALIDARG, tr("Source type %#x invalid / not supported"), source.enmType);
    3569         if (FAILED(hrc))
    3570             return hrc;
     3564        /* Check both flag groups here, as copying a directory also could mean to explicitly
     3565         * *not* replacing any existing files (or just copy files which are newer, for instance). */
     3566        GuestSession::i_directoryCopyFlagFromStr(strFlags, false /* fStrict */, &source.fDirCopyFlags);
     3567        GuestSession::i_fileCopyFlagFromStr(strFlags, false /* fStrict */, &source.fFileCopyFlags);
    35713568
    35723569        SourceSet.push_back(source);
     
    36283625        source.fDryRun      = false; /** @todo Implement support for a dry run. */
    36293626
    3630         HRESULT hrc;
    3631         if (source.enmType == FsObjType_Directory)
    3632             hrc = GuestSession::i_directoryCopyFlagFromStr(strFlags, &source.Type.Dir.fCopyFlags);
    3633         else if (source.enmType == FsObjType_File)
    3634             hrc = GuestSession::i_fileCopyFlagFromStr(strFlags, &source.Type.File.fCopyFlags);
    3635         else
    3636             return setError(E_INVALIDARG, tr("Source type %#x invalid / not supported"), source.enmType);
    3637         if (FAILED(hrc))
    3638             return hrc;
     3627        GuestSession::i_directoryCopyFlagFromStr(strFlags, false /* fStrict */, &source.fDirCopyFlags);
     3628        GuestSession::i_fileCopyFlagFromStr(strFlags, false /* fStrict */, &source.fFileCopyFlags);
    36393629
    36403630        SourceSet.push_back(source);
     
    36793669
    36803670    GuestSessionFsSourceSpec source;
    3681     source.strSource            = aSource;
    3682     source.enmType              = FsObjType_Directory;
    3683     source.enmPathStyle         = i_getGuestPathStyle();
    3684     source.fDryRun              = false; /** @todo Implement support for a dry run. */
    3685     source.Type.Dir.fCopyFlags  = (DirectoryCopyFlag_T)fFlags;
     3671    source.strSource      = aSource;
     3672    source.enmType        = FsObjType_Directory;
     3673    source.enmPathStyle   = i_getGuestPathStyle();
     3674    source.fDryRun        = false; /** @todo Implement support for a dry run. */
     3675    source.fDirCopyFlags  = (DirectoryCopyFlag_T)fFlags;
     3676    source.fFileCopyFlags = FileCopyFlag_None; /* Overwrite existing files. */
    36863677
    36873678    SourceSet.push_back(source);
     
    37083699
    37093700    GuestSessionFsSourceSpec source;
    3710     source.strSource           = aSource;
    3711     source.enmType             = FsObjType_Directory;
    3712     source.enmPathStyle        = GuestSession::i_getHostPathStyle();
    3713     source.fDryRun             = false; /** @todo Implement support for a dry run. */
    3714     source.Type.Dir.fCopyFlags = (DirectoryCopyFlag_T)fFlags;
     3701    source.strSource      = aSource;
     3702    source.enmType        = FsObjType_Directory;
     3703    source.enmPathStyle   = GuestSession::i_getHostPathStyle();
     3704    source.fDryRun        = false; /** @todo Implement support for a dry run. */
     3705    source.fDirCopyFlags  = (DirectoryCopyFlag_T)fFlags;
     3706    source.fFileCopyFlags = FileCopyFlag_None; /* Overwrite existing files. */
    37153707
    37163708    SourceSet.push_back(source);
  • trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp

    r97344 r97395  
    288288 *         VWRN_ALREADY_EXISTS if directory on the guest already exists but must not exist (\a fCanExist is \c false).
    289289 * @param  strPath                  Absolute path to directory on the guest (guest style path) to create.
     290 * @param  fMode                    Directory mode to use for creation.
    290291 * @param  enmDirectoryCreateFlags  Directory creation flags.
    291  * @param  fMode                    Directory mode to use for creation.
    292292 * @param  fFollowSymlinks          Whether to follow symlinks on the guest or not.
    293293 * @param  fCanExist                Whether the directory to create is allowed to exist already.
    294294 */
    295295int GuestSessionTask::directoryCreateOnGuest(const com::Utf8Str &strPath,
    296                                              DirectoryCreateFlag_T enmDirectoryCreateFlags, uint32_t fMode,
     296                                             uint32_t fMode, DirectoryCreateFlag_T enmDirectoryCreateFlags,
    297297                                             bool fFollowSymlinks, bool fCanExist)
    298298{
     
    355355 * @return VBox status code. VERR_ALREADY_EXISTS if directory on the guest already exists.
    356356 * @param  strPath                  Absolute path to directory on the host (host style path) to create.
     357 * @param  fMode                    Directory mode to use for creation.
    357358 * @param  fCreate                  Directory creation flags.
    358  * @param  fMode                    Directory mode to use for creation.
    359359 * @param  fCanExist                Whether the directory to create is allowed to exist already.
    360360 */
    361 int GuestSessionTask::directoryCreateOnHost(const com::Utf8Str &strPath, uint32_t fCreate, uint32_t fMode, bool fCanExist)
    362 {
    363     LogFlowFunc(("strPath=%s, fCreate=0x%x, fMode=%RU32, fCanExist=%RTbool\n", strPath.c_str(), fCreate, fMode, fCanExist));
     361int GuestSessionTask::directoryCreateOnHost(const com::Utf8Str &strPath, uint32_t fMode, uint32_t fCreate, bool fCanExist)
     362{
     363    LogFlowFunc(("strPath=%s, fMode=%RU32, fCreate=0x%x, fCanExist=%RTbool\n", strPath.c_str(), fMode, fCreate, fCanExist));
     364
     365    LogRel2(("Guest Control: Creating host directory '%s' ...\n", strPath.c_str()));
    364366
    365367    int vrc = RTDirCreate(strPath.c_str(), fMode, fCreate);
     
    502504 * Copies a file from the guest to the host.
    503505 *
    504  * @return VBox status code. VINF_NO_CHANGE if file was skipped.
    505506 * @param  strSrc               Full path of source file on the guest to copy.
    506507 * @param  strDst               Full destination path and file name (host style) to copy file to.
     
    619620    }
    620621
    621     char *pszDstFile = NULL;
    622 
    623622    if (RT_SUCCESS(vrc))
    624623    {
     
    627626            if (fFileCopyFlags & FileCopyFlag_NoReplace)
    628627            {
    629                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    630                                     Utf8StrFmt(tr("Host file \"%s\" already exists"), strDst.c_str()));
     628                setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(tr("Host file \"%s\" already exists"), strDst.c_str()));
    631629                vrc = VERR_ALREADY_EXISTS;
    632630            }
    633             else
    634                 pszDstFile = RTStrDup(strDst.c_str());
    635631        }
    636632        else if (RTFS_IS_DIRECTORY(dstObjInfo.Attr.fMode))
    637633        {
    638             /* Build the final file name with destination path (on the host). */
    639             char szDstPath[RTPATH_MAX];
    640             vrc = RTStrCopy(szDstPath, sizeof(szDstPath), strDst.c_str());
    641             if (RT_SUCCESS(vrc))
    642             {
    643                 vrc = RTPathAppend(szDstPath, sizeof(szDstPath), RTPathFilename(strSrc.c_str()));
    644                 if (RT_SUCCESS(vrc))
    645                     pszDstFile = RTStrDup(szDstPath);
    646             }
     634            setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(tr("Host destination \"%s\" is a directory"), strDst.c_str()));
     635            vrc = VERR_IS_A_DIRECTORY;
    647636        }
    648637        else if (RTFS_IS_SYMLINK(dstObjInfo.Attr.fMode))
     
    650639            if (!(fFileCopyFlags & FileCopyFlag_FollowLinks))
    651640            {
    652                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    653                                     Utf8StrFmt(tr("Host file \"%s\" is a symbolic link"),
    654                                                strDst.c_str()));
     641                setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(tr("Host destination \"%s\" is a symbolic link"), strDst.c_str()));
    655642                vrc = VERR_IS_A_SYMLINK;
    656643            }
    657             else
    658                 pszDstFile = RTStrDup(strDst.c_str());
    659644        }
    660645        else
    661646        {
    662             LogFlowThisFunc(("Object type %RU32 not implemented yet\n", dstObjInfo.Attr.fMode));
    663             vrc = VERR_NOT_IMPLEMENTED;
    664         }
    665     }
    666     else if (vrc == VERR_FILE_NOT_FOUND)
    667         pszDstFile = RTStrDup(strDst.c_str());
     647            LogFlowThisFunc(("Host file system type %#x not supported\n", dstObjInfo.Attr.fMode & RTFS_TYPE_MASK));
     648            vrc = VERR_NOT_SUPPORTED;
     649        }
     650    }
     651
     652    LogRel2(("Guest Control: Copying file '%s' from guest to '%s' on host ...\n", strSrc.c_str(), strDst.c_str()));
     653
     654    LogFlowFunc(("vrc=%Rrc, dstFsType=%#x, pszDstFile=%s\n", vrc, dstObjInfo.Attr.fMode & RTFS_TYPE_MASK, strDst.c_str()));
    668655
    669656    if (   RT_SUCCESS(vrc)
    670657        || vrc == VERR_FILE_NOT_FOUND)
    671658    {
    672         if (!pszDstFile)
    673         {
    674             setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(tr("No memory to allocate host file path")));
    675             vrc = VERR_NO_MEMORY;
     659
     660        RTFILE hDstFile;
     661        vrc = RTFileOpen(&hDstFile, strDst.c_str(),
     662                         RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
     663        if (RT_SUCCESS(vrc))
     664        {
     665            LogFlowThisFunc(("Copying '%s' to '%s' (%RI64 bytes) ...\n",
     666                             strSrc.c_str(), strDst.c_str(), srcObjData.mObjectSize));
     667
     668            vrc = fileCopyFromGuestInner(strSrc, srcFile, strDst, &hDstFile, fFileCopyFlags,
     669                                         0 /* Offset, unused */, (uint64_t)srcObjData.mObjectSize);
     670
     671            int vrc2 = RTFileClose(hDstFile);
     672            AssertRC(vrc2);
    676673        }
    677674        else
    678         {
    679             RTFILE hDstFile;
    680             vrc = RTFileOpen(&hDstFile, pszDstFile,
    681                              RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
    682             if (RT_SUCCESS(vrc))
    683             {
    684                 LogFlowThisFunc(("Copying '%s' to '%s' (%RI64 bytes) ...\n",
    685                                  strSrc.c_str(), pszDstFile, srcObjData.mObjectSize));
    686 
    687                 vrc = fileCopyFromGuestInner(strSrc, srcFile, pszDstFile, &hDstFile, fFileCopyFlags,
    688                                              0 /* Offset, unused */, (uint64_t)srcObjData.mObjectSize);
    689 
    690                 int vrc2 = RTFileClose(hDstFile);
    691                 AssertRC(vrc2);
    692             }
    693             else
    694                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    695                                     Utf8StrFmt(tr("Opening/creating host file \"%s\" failed: %Rrc"),
    696                                                pszDstFile, vrc));
    697         }
    698     }
    699 
    700     RTStrFree(pszDstFile);
     675            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     676                                Utf8StrFmt(tr("Opening/creating host file \"%s\" failed: %Rrc"), strDst.c_str(), vrc));
     677    }
    701678
    702679    int vrc2 = srcFile->i_closeFile(&vrcGuest);
     
    819796 * Copies a file from the guest to the host.
    820797 *
    821  * @return VBox status code. VINF_NO_CHANGE if file was skipped.
    822798 * @param  strSrc               Full path of source file on the host to copy.
    823799 * @param  strDst               Full destination path and file name (guest style) to copy file to.
     
    828804    LogFlowThisFunc(("strSource=%s, strDst=%s, fFileCopyFlags=0x%x\n", strSrc.c_str(), strDst.c_str(), fFileCopyFlags));
    829805
    830     Utf8Str strDstFinal = strDst;
    831 
    832806    GuestFileOpenInfo dstOpenInfo;
    833     dstOpenInfo.mFilename        = strDstFinal;
     807    dstOpenInfo.mFilename        = strDst;
    834808    if (fFileCopyFlags & FileCopyFlag_NoReplace)
    835809        dstOpenInfo.mOpenAction  = FileOpenAction_CreateNew;
     
    877851                {
    878852                    GuestFsObjData dstObjData;
    879                     vrc = mSession->i_fileQueryInfo(strDstFinal, RT_BOOL(fFileCopyFlags & FileCopyFlag_FollowLinks), dstObjData,
     853                    vrc = mSession->i_fileQueryInfo(strDst, RT_BOOL(fFileCopyFlags & FileCopyFlag_FollowLinks), dstObjData,
    880854                                                    &vrcGuest);
    881855                    if (RT_SUCCESS(vrc))
     
    886860                        {
    887861                            LogRel2(("Guest Control: Guest file \"%s\" has same or newer modification date, skipping",
    888                                      strDstFinal.c_str()));
     862                                     strDst.c_str()));
    889863                            fSkip = true;
    890864                        }
     
    903877                                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    904878                                                        Utf8StrFmt(tr("Guest error while determining object data for guest file \"%s\": %Rrc"),
    905                                                            strDstFinal.c_str(), vrcGuest));
     879                                                                   strDst.c_str(), vrcGuest));
    906880                                    break;
    907881                            }
     
    910884                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    911885                                                Utf8StrFmt(tr("Host error while determining object data for guest file \"%s\": %Rrc"),
    912                                                            strDstFinal.c_str(), vrc));
     886                                                           strDst.c_str(), vrc));
    913887                    }
    914888                }
     
    932906    if (RT_SUCCESS(vrc))
    933907    {
     908        LogRel2(("Guest Control: Copying file '%s' from host to '%s' on guest ...\n", strSrc.c_str(), strDst.c_str()));
     909
    934910        RTVFSFILE hSrcFile;
    935911        vrc = RTVfsFileOpenNormal(szSrcReal, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, &hSrcFile);
     
    937913        {
    938914            LogFlowThisFunc(("Copying '%s' to '%s' (%RI64 bytes) ...\n",
    939                              szSrcReal, strDstFinal.c_str(), srcObjInfo.cbObject));
    940 
    941             vrc = fileCopyToGuestInner(szSrcReal, hSrcFile, strDstFinal, dstFile,
     915                             szSrcReal, strDst.c_str(), srcObjInfo.cbObject));
     916
     917            vrc = fileCopyToGuestInner(szSrcReal, hSrcFile, strDst, dstFile,
    942918                                       fFileCopyFlags, 0 /* Offset, unused */, srcObjInfo.cbObject);
    943919
     
    1003979    {
    1004980        pEntry = new FsEntry();
    1005         pEntry->fMode = pcObjInfo->Attr.fMode & RTFS_TYPE_MASK;
     981        pEntry->fMode = pcObjInfo->Attr.fMode;
    1006982        pEntry->strPath = strFile;
    1007983
     
    10461022     *       will be done directly when working on those. See @bugref{10139}. */
    10471023
    1048     LogFlowFunc(("mSrcRootAbs=%s, mDstRootAbs=%s, fCopyFlags=%#x\n",
    1049                  mSrcRootAbs.c_str(), mDstRootAbs.c_str(), mSourceSpec.Type.Dir.fCopyFlags));
     1024    LogFlowFunc(("mSrcRootAbs=%s, mDstRootAbs=%s, fDirCopyFlags=%#x, fFileCopyFlags=%#x\n",
     1025                 mSrcRootAbs.c_str(), mDstRootAbs.c_str(), mSourceSpec.fDirCopyFlags, mSourceSpec.fFileCopyFlags));
    10501026
    10511027    return VINF_SUCCESS;
     
    10721048    LogFlowFuncLeave();
    10731049}
     1050
     1051#ifdef DEBUG
     1052/**
     1053 * Dumps a FsList to the debug log.
     1054 */
     1055void FsList::DumpToLog(void)
     1056{
     1057    LogFlowFunc(("strSrcRootAbs=%s, strDstRootAbs=%s\n", mSrcRootAbs.c_str(), mDstRootAbs.c_str()));
     1058
     1059    FsEntries::iterator itEntry = mVecEntries.begin();
     1060    while (itEntry != mVecEntries.end())
     1061    {
     1062        FsEntry *pEntry = *itEntry;
     1063        LogFlowFunc(("\tstrPath=%s (fMode %#x)\n", pEntry->strPath.c_str(), pEntry->fMode));
     1064        ++itEntry;
     1065    }
     1066
     1067    LogFlowFuncLeave();
     1068}
     1069#endif /* DEBUG */
    10741070
    10751071/**
     
    11621158                    LogRel2(("Guest Control: Directory '%s'\n", strEntry.c_str()));
    11631159
    1164                     if (!(mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_Recursive))
     1160                    if (!(mSourceSpec.fDirCopyFlags & DirectoryCopyFlag_Recursive))
    11651161                        break;
    11661162
     
    11711167                case FsObjType_Symlink:
    11721168                {
    1173                     if (mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_FollowLinks)
     1169                    if (   mSourceSpec.fDirCopyFlags  & DirectoryCopyFlag_FollowLinks
     1170                        || mSourceSpec.fFileCopyFlags & FileCopyFlag_FollowLinks)
    11741171                    {
    11751172                        /** @todo Symlink handling from guest is not implemented yet.
     
    12761273                                LogRel2(("Guest Control: Directory '%s'\n", strEntry.c_str()));
    12771274
    1278                                 if (!(mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_Recursive))
     1275                                if (!(mSourceSpec.fDirCopyFlags & DirectoryCopyFlag_Recursive))
    12791276                                    break;
    12801277
     
    12931290                            case RTFS_TYPE_SYMLINK:
    12941291                            {
    1295                                 if (mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_FollowLinks)
     1292                                Utf8Str strEntryAbs = strPathAbs + (const char *)pDirEntry->szName;
     1293
     1294                                vrc = RTPathReal(strEntryAbs.c_str(), pszPathReal, cbPathReal);
     1295                                if (RT_SUCCESS(vrc))
    12961296                                {
    1297                                     Utf8Str strEntryAbs = strPathAbs + (const char *)pDirEntry->szName;
    1298 
    1299                                     vrc = RTPathReal(strEntryAbs.c_str(), pszPathReal, cbPathReal);
     1297                                    vrc = RTPathQueryInfo(pszPathReal, &objInfo, RTFSOBJATTRADD_NOTHING);
    13001298                                    if (RT_SUCCESS(vrc))
    13011299                                    {
    1302                                         vrc = RTPathQueryInfo(pszPathReal, &objInfo, RTFSOBJATTRADD_NOTHING);
    1303                                         if (RT_SUCCESS(vrc))
     1300                                        if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
    13041301                                        {
    1305                                             if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
    1306                                             {
    1307                                                 LogRel2(("Guest Control: Symbolic link '%s' -> '%s' (directory)\n",
    1308                                                          strEntryAbs.c_str(), pszPathReal));
     1302                                            LogRel2(("Guest Control: Symbolic link '%s' -> '%s' (directory)\n",
     1303                                                     strEntryAbs.c_str(), pszPathReal));
     1304                                            if (mSourceSpec.fDirCopyFlags  & DirectoryCopyFlag_FollowLinks)
    13091305                                                vrc = AddDirFromHost(strPath, strEntry, pszPathReal, cbPathReal, pDirEntry);
    1310                                             }
    1311                                             else if (RTFS_IS_FILE(objInfo.Attr.fMode))
    1312                                             {
    1313                                                 LogRel2(("Guest Control: Symbolic link '%s' -> '%s' (file)\n",
    1314                                                          strEntryAbs.c_str(), pszPathReal));
     1306                                        }
     1307                                        else if (RTFS_IS_FILE(objInfo.Attr.fMode))
     1308                                        {
     1309                                            LogRel2(("Guest Control: Symbolic link '%s' -> '%s' (file)\n",
     1310                                                     strEntryAbs.c_str(), pszPathReal));
     1311                                            if (mSourceSpec.fFileCopyFlags & DirectoryCopyFlag_FollowLinks)
    13151312                                                vrc = AddEntryFromHost(strEntry, &objInfo);
    1316                                             }
    1317                                             else
    1318                                                 vrc = VERR_NOT_SUPPORTED;
    13191313                                        }
    1320 
    1321                                         if (RT_FAILURE(vrc))
    1322                                             LogRel2(("Guest Control: Unable to query symbolic link info for '%s', rc=%Rrc\n",
    1323                                                      pszPathReal, vrc));
     1314                                        else
     1315                                            vrc = VERR_NOT_SUPPORTED;
    13241316                                    }
    1325                                     else
    1326                                     {
    1327                                         LogRel2(("Guest Control: Unable to resolve symlink for '%s', rc=%Rrc\n", strPathAbs.c_str(), vrc));
    1328                                         if (vrc == VERR_FILE_NOT_FOUND) /* Broken symlink, skip. */
    1329                                             vrc = VINF_SUCCESS;
    1330                                     }
     1317
     1318                                    if (RT_FAILURE(vrc))
     1319                                        LogRel2(("Guest Control: Unable to query symbolic link info for '%s', rc=%Rrc\n",
     1320                                                 pszPathReal, vrc));
    13311321                                }
    13321322                                else
    1333                                     LogRel2(("Guest Control: Symbolic link '%s' (skipped)\n", strEntry.c_str()));
     1323                                {
     1324                                    LogRel2(("Guest Control: Unable to resolve symlink for '%s', rc=%Rrc\n", strPathAbs.c_str(), vrc));
     1325                                    if (vrc == VERR_FILE_NOT_FOUND) /* Broken symlink, skip. */
     1326                                        vrc = VINF_SUCCESS;
     1327                                }
    13341328                                break;
    13351329                            }
     
    14751469            if (itSrc->enmType == FsObjType_Directory)
    14761470            {
    1477                 /* If the source does not end with a slash, copy over the entire directory
    1478                  * (and not just its contents). */
    1479                 if (!strSrc.endsWith(mstrGuestPathStyle))
    1480                 {
    1481                     if (!RTPATH_IS_SLASH(strDst[strDst.length() - 1]))
    1482                         strDst += RTPATH_SLASH_STR;
    1483 
    1484                     strDst += Utf8Str(RTPathFilename(strSrc.c_str()));
    1485                 }
    1486 
    1487                 fFollowSymlinks = itSrc->Type.Dir.fCopyFlags & DirectoryCopyFlag_FollowLinks;
     1471                fFollowSymlinks = itSrc->fDirCopyFlags & DirectoryCopyFlag_FollowLinks;
    14881472            }
    14891473            else
    14901474            {
    1491                 fFollowSymlinks = RT_BOOL(itSrc->Type.File.fCopyFlags & FileCopyFlag_FollowLinks);
    1492             }
    1493 
    1494             LogFlowFunc(("strSrc=%s, strDst=%s, fFollowSymlinks=%RTbool\n", strSrc.c_str(), strDst.c_str(), fFollowSymlinks));
     1475                fFollowSymlinks = RT_BOOL(itSrc->fFileCopyFlags & FileCopyFlag_FollowLinks);
     1476            }
     1477
     1478            LogFlowFunc(("strSrc=%s (path style is %s), strDst=%s, fFollowSymlinks=%RTbool\n",
     1479                         strSrc.c_str(), GuestBase::pathStyleToStr(itSrc->enmPathStyle), strDst.c_str(), fFollowSymlinks));
    14951480
    14961481            GuestFsObjData srcObjData;
     
    15001485            {
    15011486                if (vrc == VERR_GSTCTL_GUEST_ERROR)
    1502                     strErrorInfo = GuestBase::getErrorAsString(tr("Guest file lookup failed"),
     1487                    strErrorInfo = GuestBase::getErrorAsString(tr("Guest source lookup failed"),
    15031488                                                               GuestErrorInfo(GuestErrorInfo::Type_ToolStat, vrcGuest, strSrc.c_str()));
    15041489                else
    1505                     strErrorInfo.printf(tr("Guest file lookup for \"%s\" failed: %Rrc"),
     1490                    strErrorInfo.printf(tr("Guest source lookup for \"%s\" failed: %Rrc"),
    15061491                                        strSrc.c_str(), vrc);
    15071492                break;
     
    15341519                if (RT_SUCCESS(vrc))
    15351520                {
    1536                     if (itSrc->enmType == FsObjType_Directory)
    1537                         vrc = pFsList->AddDirFromGuest(strSrc);
    1538                     else
    1539                         vrc = pFsList->AddEntryFromGuest(RTPathFilename(strSrc.c_str()), srcObjData);
     1521                    switch (itSrc->enmType)
     1522                    {
     1523                        case FsObjType_Directory:
     1524                        {
     1525                            vrc = pFsList->AddDirFromGuest(strSrc);
     1526                            break;
     1527                        }
     1528
     1529                        case FsObjType_File:
     1530                            /* The file name is already part of the actual list's source root (strSrc). */
     1531                            break;
     1532
     1533                        default:
     1534                            LogRel2(("Guest Control: Warning: Unknown guest file system type %#x for source \"%s\", skipping\n",
     1535                                     itSrc->enmType, strSrc.c_str()));
     1536                            break;
     1537                    }
    15401538                }
    15411539
     
    15471545                    break;
    15481546                }
    1549 
     1547#ifdef DEBUG
     1548                pFsList->DumpToLog();
     1549#endif
    15501550                mVecLists.push_back(pFsList);
    15511551            }
     
    16081608        Utf8Str strDstRootAbs = pList->mDstRootAbs;
    16091609
    1610         const bool     fCopyIntoExisting = pList->mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_CopyIntoExisting;
    1611         const bool     fFollowSymlinks   = true; /** @todo */
    1612         const uint32_t fDirMode          = 0700; /** @todo Play safe by default; implement ACLs. */
    1613         uint32_t       fDirCreate        = 0;
    1614 
    1615         if (!fFollowSymlinks)
    1616             fDirCreate |= RTDIRCREATE_FLAGS_NO_SYMLINKS;
     1610        GuestPath::BuildDestinationPath(strSrcRootAbs, mSession->i_getGuestPathStyle(),
     1611                                        strDstRootAbs, PATH_STYLE_NATIVE);
     1612
     1613        bool fCopyIntoExisting;
     1614        bool fFollowSymlinks;
     1615
     1616        if (pList->mSourceSpec.enmType == FsObjType_Directory)
     1617        {
     1618            fCopyIntoExisting = RT_BOOL(pList->mSourceSpec.fDirCopyFlags & DirectoryCopyFlag_CopyIntoExisting);
     1619            fFollowSymlinks   = RT_BOOL(pList->mSourceSpec.fDirCopyFlags & DirectoryCopyFlag_FollowLinks);
     1620        }
     1621        else if (pList->mSourceSpec.enmType == FsObjType_File)
     1622        {
     1623            fCopyIntoExisting = !RT_BOOL(pList->mSourceSpec.fFileCopyFlags & FileCopyFlag_NoReplace);
     1624            fFollowSymlinks   = RT_BOOL(pList->mSourceSpec.fFileCopyFlags & FileCopyFlag_FollowLinks);
     1625        }
     1626        else
     1627            AssertFailedBreakStmt(vrc = VERR_NOT_IMPLEMENTED);
     1628
     1629        uint32_t const  fDirMode          = 0700; /** @todo Play safe by default; implement ACLs. */
     1630        uint32_t        fDirCreate        = 0;
     1631
     1632        bool            fDstExists        = true;
    16171633
    16181634        RTFSOBJINFO ObjInfo;
    16191635        RT_ZERO(ObjInfo);
    1620         vrc = RTPathQueryInfo(strDstRootAbs.c_str(), &ObjInfo, RTFSOBJATTRADD_NOTHING);
    1621         if (   RT_FAILURE(vrc)
    1622             && vrc != VERR_FILE_NOT_FOUND
    1623             && vrc != VERR_PATH_NOT_FOUND)
    1624         {
    1625             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1626                                 Utf8StrFmt(tr("Host path lookup for \"%s\" failed: %Rrc"), strDstRootAbs.c_str(), vrc));
    1627             break;
    1628         }
    1629         else
    1630             vrc = VINF_SUCCESS; /* Reset rc. */
    1631 
    1632         bool const fDstIsDir        = RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode);
    1633         bool const fDstDirMustExist = strDstRootAbs.endsWith(PATH_STYLE_SEP_STR(PATH_STYLE_NATIVE)); /* Copy into existing dir? */
    1634 
    1635         /* Copy source(s) into an existing directory on the host (path ends with a slash)? */
    1636         if (fDstDirMustExist)
    1637         {
    1638             if (   !RTDirExists(strDstRootAbs.c_str())
    1639                 || !fDstIsDir)
     1636        vrc = RTPathQueryInfoEx(strDstRootAbs.c_str(), &ObjInfo, RTFSOBJATTRADD_NOTHING,
     1637                                fFollowSymlinks ? RTPATH_F_FOLLOW_LINK : RTPATH_F_ON_LINK /* fFlags */);
     1638        if (RT_FAILURE(vrc))
     1639        {
     1640            if (   vrc == VERR_FILE_NOT_FOUND
     1641                || vrc == VERR_PATH_NOT_FOUND)
     1642            {
     1643                fDstExists = false;
     1644                vrc        = VINF_SUCCESS;
     1645            }
     1646            else
    16401647            {
    16411648                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1642                                     Utf8StrFmt(tr("Host directory \"%s\" does not exist"), strDstRootAbs.c_str()));
    1643                 vrc = VERR_PATH_NOT_FOUND;
     1649                                    Utf8StrFmt(tr("Host path lookup for \"%s\" failed: %Rrc"), strDstRootAbs.c_str(), vrc));
    16441650                break;
    16451651            }
    16461652        }
    1647         /* else Copy source(s) into a file on the host. */
    1648 
    1649         /* Create the destination directory if required. */
    1650         if (   pList->mSourceSpec.enmType == FsObjType_Directory
    1651             && pList->mSourceSpec.fDryRun == false)
    1652         {
    1653             vrc = directoryCreateOnHost(strDstRootAbs, fDirCreate, fDirMode, fCopyIntoExisting);
     1653
     1654        /* Create the root directory. */
     1655        if (pList->mSourceSpec.enmType == FsObjType_Directory)
     1656        {
     1657            LogFlowFunc(("Directory: fDirCopyFlags=%#x, fCopyIntoExisting=%RTbool, fFollowSymlinks=%RTbool\n",
     1658                         pList->mSourceSpec.fDirCopyFlags, fCopyIntoExisting, fFollowSymlinks));
     1659
     1660            if (fDstExists)
     1661            {
     1662                switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
     1663                {
     1664                    case RTFS_TYPE_DIRECTORY:
     1665                    {
     1666                        if (!fCopyIntoExisting)
     1667                        {
     1668                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1669                                                Utf8StrFmt(tr("Host root directory \"%s\" already exists"), strDstRootAbs.c_str()));
     1670                            vrc = VERR_ALREADY_EXISTS;
     1671                            break;
     1672                        }
     1673                        break;
     1674                    }
     1675
     1676                    case RTFS_TYPE_FILE:
     1677                    {
     1678                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1679                                            Utf8StrFmt(tr("Destination \"%s\" on the host already exists and is a file"), strDstRootAbs.c_str()));
     1680                        vrc = VERR_IS_A_FILE;
     1681                        break;
     1682                    }
     1683
     1684                    default:
     1685                    {
     1686                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1687                                            Utf8StrFmt(tr("Unknown object type (%#x) on host for \"%s\""),
     1688                                                       ObjInfo.Attr.fMode & RTFS_TYPE_MASK, strDstRootAbs.c_str()));
     1689                        vrc = VERR_NOT_SUPPORTED;
     1690                        break;
     1691                    }
     1692                }
     1693            }
     1694
    16541695            if (RT_FAILURE(vrc))
    16551696                break;
    1656         }
    1657 
    1658         FsEntries::const_iterator itEntry = pList->mVecEntries.begin();
    1659         while (itEntry != pList->mVecEntries.end())
    1660         {
    1661             FsEntry *pEntry = *itEntry;
    1662             AssertPtr(pEntry);
    1663 
    1664             Utf8Str strSrcAbs = strSrcRootAbs;
    1665             Utf8Str strDstAbs = strDstRootAbs;
    1666 
    1667             if (pList->mSourceSpec.enmType == FsObjType_Directory)
    1668             {
     1697
     1698            /* Clean up the final host destination root path (for cleaning up mixed path separators). */
     1699            vrc = GuestPath::Translate(strDstRootAbs,
     1700                                       PATH_STYLE_NATIVE /* Source */, PATH_STYLE_NATIVE /* Dest */, true /* fForce */);
     1701            if (RT_FAILURE(vrc))
     1702            {
     1703                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1704                                    Utf8StrFmt(tr("Translating host destination root path '%s' failed: %Rrc"),
     1705                                               strDstRootAbs.c_str(), vrc));
     1706                break;
     1707            }
     1708
     1709            /* Make sure the destination root directory exists. */
     1710            if (pList->mSourceSpec.fDryRun == false)
     1711            {
     1712                vrc = directoryCreateOnHost(strDstRootAbs, fDirMode, 0 /* fCreate */, true /* fCanExist */);
     1713                if (RT_FAILURE(vrc))
     1714                    break;
     1715            }
     1716
     1717            AssertBreakStmt(pList->mSourceSpec.enmType == FsObjType_Directory, vrc = VERR_NOT_SUPPORTED);
     1718
     1719            /* Walk the entries. */
     1720            FsEntries::const_iterator itEntry = pList->mVecEntries.begin();
     1721            while (itEntry != pList->mVecEntries.end())
     1722            {
     1723                FsEntry *pEntry = *itEntry;
     1724                AssertPtr(pEntry);
     1725
     1726                Utf8Str strSrcAbs = strSrcRootAbs;
     1727                Utf8Str strDstAbs = strDstRootAbs;
     1728
    16691729                strSrcAbs += PATH_STYLE_SEP_STR(pList->mSourceSpec.enmPathStyle);
    16701730                strSrcAbs += pEntry->strPath;
    1671             }
    1672 
    1673             if (fDstIsDir)
    1674             {
     1731
    16751732                strDstAbs += PATH_STYLE_SEP_STR(PATH_STYLE_NATIVE);
    16761733                strDstAbs += pEntry->strPath;
    1677             }
    1678 
    1679             /* Translate the final guest source path (for cleaning up mixed path separators). */
    1680             vrc = GuestPath::Translate(strSrcAbs, pList->mSourceSpec.enmPathStyle /* Source */, pList->mSourceSpec.enmPathStyle /* Dest */,
    1681                                        true /* fForce */);
    1682             if (RT_FAILURE(vrc))
    1683                 break;
    1684 
    1685             /* Translate the final host destination path (for cleaning up mixed path separators). */
    1686             vrc = GuestPath::Translate(strDstAbs, PATH_STYLE_NATIVE, PATH_STYLE_NATIVE /* Dest */, true /* fForce */);
    1687             if (RT_FAILURE(vrc))
    1688                 break;
    1689 
    1690             mProgress->SetNextOperation(Bstr(strSrcAbs).raw(), 1);
    1691 
    1692             LogRel2(("Guest Control: Copying '%s' from guest to '%s' on host ...\n", strSrcAbs.c_str(), strDstAbs.c_str()));
    1693 
    1694             switch (pEntry->fMode & RTFS_TYPE_MASK)
    1695             {
    1696                 case RTFS_TYPE_DIRECTORY:
    1697                     LogRel2(("Guest Control: Copying directory '%s' from guest to '%s' on host ...\n", strSrcAbs.c_str(), strDstAbs.c_str()));
    1698                     if (!pList->mSourceSpec.fDryRun)
    1699                         vrc = directoryCreateOnHost(strDstAbs, fDirCreate, fDirMode, fCopyIntoExisting);
     1734
     1735                /* Clean up the final guest source path (for cleaning up mixed path separators). */
     1736                vrc = GuestPath::Translate(strSrcAbs, pList->mSourceSpec.enmPathStyle /* Source */, pList->mSourceSpec.enmPathStyle /* Dest */,
     1737                                           true /* fForce */);
     1738                if (RT_FAILURE(vrc))
     1739                {
     1740                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1741                                        Utf8StrFmt(tr("Translating guest source path '%s' from %s to %s failed: %Rrc"),
     1742                                                   strSrcAbs.c_str(),
     1743                                                   GuestBase::pathStyleToStr(pList->mSourceSpec.enmPathStyle),
     1744                                                   GuestBase::pathStyleToStr(pList->mSourceSpec.enmPathStyle), vrc));
    17001745                    break;
    1701 
    1702                 case RTFS_TYPE_FILE:
    1703                     RT_FALL_THROUGH();
    1704                 case RTFS_TYPE_SYMLINK:
    1705                     LogRel2(("Guest Control: Copying %s '%s' from guest to '%s' on host ...\n",
    1706                              (pEntry->fMode & RTFS_TYPE_MASK) == RTFS_TYPE_SYMLINK ? "symlink" : "file", strSrcAbs.c_str(), strDstAbs.c_str()));
    1707                     if (!pList->mSourceSpec.fDryRun)
    1708                         vrc = fileCopyFromGuest(strSrcAbs, strDstAbs, FileCopyFlag_None);
     1746                }
     1747
     1748                /* Translate the final host destination path. */
     1749                vrc = GuestPath::Translate(strDstAbs, pList->mSourceSpec.enmPathStyle, PATH_STYLE_NATIVE /* Source */, true /* fForce */);
     1750                if (RT_FAILURE(vrc))
     1751                {
     1752                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1753                                        Utf8StrFmt(tr("Translating host destination path '%s' from %s to %s failed: %Rrc"),
     1754                                                   strDstAbs.c_str(),
     1755                                                   GuestBase::pathStyleToStr(pList->mSourceSpec.enmPathStyle),
     1756                                                   GuestBase::pathStyleToStr(PATH_STYLE_NATIVE), vrc));
    17091757                    break;
    1710 
    1711                 default:
    1712                     LogFlowFunc(("Warning: Type %d for '%s' is not supported\n",
    1713                                  pEntry->fMode & RTFS_TYPE_MASK, strSrcAbs.c_str()));
     1758                }
     1759
     1760                mProgress->SetNextOperation(Bstr(strSrcAbs).raw(), 1);
     1761
     1762                switch (pEntry->fMode & RTFS_TYPE_MASK)
     1763                {
     1764                    case RTFS_TYPE_DIRECTORY:
     1765                        if (!pList->mSourceSpec.fDryRun)
     1766                            vrc = directoryCreateOnHost(strDstAbs, fDirMode, fDirCreate, fCopyIntoExisting);
     1767                        break;
     1768
     1769                    case RTFS_TYPE_FILE:
     1770                        RT_FALL_THROUGH();
     1771                    case RTFS_TYPE_SYMLINK:
     1772                        if (!pList->mSourceSpec.fDryRun)
     1773                            vrc = fileCopyFromGuest(strSrcAbs, strDstAbs, pList->mSourceSpec.fFileCopyFlags);
     1774                        break;
     1775
     1776                    default:
     1777                        AssertFailed(); /* Should never happen (we already have a filtered list). */
     1778                        break;
     1779                }
     1780
     1781                if (RT_FAILURE(vrc))
    17141782                    break;
    1715             }
    1716 
    1717             if (RT_FAILURE(vrc))
    1718                 break;
    1719 
    1720             ++itEntry;
    1721         }
     1783
     1784                ++itEntry;
     1785            }
     1786        }
     1787        else if (pList->mSourceSpec.enmType == FsObjType_File)
     1788        {
     1789            LogFlowFunc(("File: fFileCopyFlags=%#x, fCopyIntoExisting=%RTbool, fFollowSymlinks=%RTbool\n",
     1790                         pList->mSourceSpec.fFileCopyFlags, fCopyIntoExisting, fFollowSymlinks));
     1791
     1792            if (fDstExists)
     1793            {
     1794                switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
     1795                {
     1796                    case RTFS_TYPE_DIRECTORY:
     1797                    {
     1798                        if (!fCopyIntoExisting)
     1799                        {
     1800                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1801                                                Utf8StrFmt(tr("Destination \"%s\" on the host already exists and is a directory"),
     1802                                                           strDstRootAbs.c_str()));
     1803                            vrc = VERR_IS_A_DIRECTORY;
     1804                            break;
     1805                        }
     1806                        break;
     1807                    }
     1808
     1809                    case RTFS_TYPE_FILE:
     1810                    {
     1811                        if (!fCopyIntoExisting)
     1812                        {
     1813                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1814                                                Utf8StrFmt(tr("Host file \"%s\" already exists"), strDstRootAbs.c_str()));
     1815                            vrc = VERR_ALREADY_EXISTS;
     1816                        }
     1817                        break;
     1818                    }
     1819
     1820                    default:
     1821                    {
     1822                        /** @ŧodo Resolve symlinks? */
     1823                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1824                                            Utf8StrFmt(tr("Unknown object type (%#x) on host for \"%s\""),
     1825                                                       ObjInfo.Attr.fMode & RTFS_TYPE_MASK, strDstRootAbs.c_str()));
     1826                        vrc = VERR_NOT_SUPPORTED;
     1827                        break;
     1828                    }
     1829                }
     1830            }
     1831
     1832            if (!pList->mSourceSpec.fDryRun)
     1833                vrc = fileCopyFromGuest(strSrcRootAbs, strDstRootAbs, pList->mSourceSpec.fFileCopyFlags);
     1834        }
     1835        else
     1836            AssertFailedStmt(vrc = VERR_NOT_SUPPORTED);
    17221837
    17231838        if (RT_FAILURE(vrc))
     
    17931908            Utf8Str strDst = mDest;
    17941909
    1795             LogFlowFunc(("strSrc=%s, strDst=%s\n", strSrc.c_str(), strDst.c_str()));
     1910            bool    fFollowSymlinks;
    17961911
    17971912            if (strSrc.isEmpty())
     
    18021917            }
    18031918
     1919            if (itSrc->enmType == FsObjType_Directory)
     1920            {
     1921                fFollowSymlinks = itSrc->fDirCopyFlags & DirectoryCopyFlag_FollowLinks;
     1922            }
     1923            else
     1924            {
     1925                fFollowSymlinks = RT_BOOL(itSrc->fFileCopyFlags & FileCopyFlag_FollowLinks);
     1926            }
     1927
     1928            LogFlowFunc(("strSrc=%s (path style is %s), strDst=%s\n",
     1929                         strSrc.c_str(), GuestBase::pathStyleToStr(itSrc->enmPathStyle), strDst.c_str()));
     1930
    18041931            RTFSOBJINFO srcFsObjInfo;
    1805             vrc = RTPathQueryInfo(strSrc.c_str(), &srcFsObjInfo, RTFSOBJATTRADD_NOTHING);
     1932            vrc = RTPathQueryInfoEx(strSrc.c_str(), &srcFsObjInfo, RTFSOBJATTRADD_NOTHING,
     1933                                    fFollowSymlinks ? RTPATH_F_FOLLOW_LINK : RTPATH_F_ON_LINK /* fFlags */);
    18061934            if (RT_FAILURE(vrc))
    18071935            {
     
    18361964                if (RT_SUCCESS(vrc))
    18371965                {
    1838                     if (itSrc->enmType == FsObjType_Directory)
     1966                    switch (itSrc->enmType)
    18391967                    {
    1840                         char szPathReal[RTPATH_MAX];
    1841                         RTDIRENTRYEX DirEntry;
    1842                         vrc = pFsList->AddDirFromHost(strSrc /* strPath */, "" /* strSubDir */,
    1843                                                       szPathReal, sizeof(szPathReal), &DirEntry);
     1968                        case FsObjType_Directory:
     1969                        {
     1970                            char szPathReal[RTPATH_MAX];
     1971                            RTDIRENTRYEX DirEntry;
     1972                            vrc = pFsList->AddDirFromHost(strSrc /* strPath */, "" /* strSubDir */,
     1973                                                          szPathReal, sizeof(szPathReal), &DirEntry);
     1974                        }
     1975
     1976                        case FsObjType_File:
     1977                            /* The file name is already part of the actual list's source root (strSrc). */
     1978                            break;
     1979
     1980                        default:
     1981                            LogRel2(("Guest Control: Warning: Unknown guest host system type %#x for source \"%s\", skipping\n",
     1982                                     itSrc->enmType, strSrc.c_str()));
     1983                            break;
    18441984                    }
    1845                     else
    1846                         vrc = pFsList->AddEntryFromHost(RTPathFilename(strSrc.c_str()), &srcFsObjInfo);
    18471985                }
    18481986
     
    18541992                    break;
    18551993                }
    1856 
     1994#ifdef DEBUG
     1995                pFsList->DumpToLog();
     1996#endif
    18571997                mVecLists.push_back(pFsList);
    18581998            }
     
    19152055        Utf8Str strDstRootAbs = pList->mDstRootAbs;
    19162056
    1917         /* Translate the destination path from the host to a path compatible with the guest. */
    1918         vrc = GuestPath::Translate(strDstRootAbs, PATH_STYLE_NATIVE /* Source */, mSession->i_getGuestPathStyle() /* Dest */);
     2057        GuestPath::BuildDestinationPath(strSrcRootAbs, PATH_STYLE_NATIVE,
     2058                                        strDstRootAbs, mSession->i_getGuestPathStyle());
     2059
     2060        /* Translate the destination path from the host to a path compatible with the guest.
     2061         * strDstRootAbs already is in the destination path style, so just do a path cleanup. */
     2062        vrc = GuestPath::Translate(strDstRootAbs,
     2063                                   mSession->i_getGuestPathStyle() /* Source */, mSession->i_getGuestPathStyle() /* Dest */,
     2064                                   true /* fForce */);
    19192065        if (RT_FAILURE(vrc))
     2066        {
     2067            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2068                                Utf8StrFmt(tr("Translating guest destination path '%s' from %s to %s failed: %Rrc"),
     2069                                           strDstRootAbs.c_str(),
     2070                                           GuestBase::pathStyleToStr(PATH_STYLE_NATIVE),
     2071                                           GuestBase::pathStyleToStr(mSession->i_getGuestPathStyle()), vrc));
    19202072            break;
    1921 
    1922         bool     fCopyIntoExisting = false;
    1923         bool     fFollowSymlinks   = false;
    1924         uint32_t fDirMode          = 0700; /** @todo Play safe by default; implement ACLs. */
     2073        }
     2074
     2075        bool fCopyIntoExisting;
     2076        bool fFollowSymlinks;
     2077
     2078        if (pList->mSourceSpec.enmType == FsObjType_Directory)
     2079        {
     2080            fCopyIntoExisting = RT_BOOL(pList->mSourceSpec.fDirCopyFlags & DirectoryCopyFlag_CopyIntoExisting);
     2081            fFollowSymlinks   = RT_BOOL(pList->mSourceSpec.fDirCopyFlags & DirectoryCopyFlag_FollowLinks);
     2082        }
     2083        else if (pList->mSourceSpec.enmType == FsObjType_File)
     2084        {
     2085            fCopyIntoExisting = !RT_BOOL(pList->mSourceSpec.fFileCopyFlags & FileCopyFlag_NoReplace);
     2086            fFollowSymlinks   = RT_BOOL(pList->mSourceSpec.fFileCopyFlags & FileCopyFlag_FollowLinks);
     2087        }
     2088        else
     2089            AssertFailedBreakStmt(vrc = VERR_NOT_IMPLEMENTED);
     2090
     2091        uint32_t const fDirMode          = 0700; /** @todo Play safe by default; implement ACLs. */
     2092
     2093        bool           fDstExists        = true;
    19252094
    19262095        GuestFsObjData dstObjData;
    19272096        int vrcGuest;
    1928         vrc = mSession->i_fsQueryInfo(strDstRootAbs, pList->mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_FollowLinks,
    1929                                       dstObjData, &vrcGuest);
     2097        vrc = mSession->i_fsQueryInfo(strDstRootAbs, fFollowSymlinks, dstObjData, &vrcGuest);
    19302098        if (RT_FAILURE(vrc))
    19312099        {
     
    19372105                        RT_FALL_THROUGH();
    19382106                    case VERR_FILE_NOT_FOUND:
    1939                         /* We will deal with this down below. */
    1940                         vrc = VINF_SUCCESS;
     2107                    {
     2108                        fDstExists = false;
     2109                        vrc        = VINF_SUCCESS;
    19412110                        break;
     2111                    }
    19422112                    default:
    19432113                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     
    19562126        }
    19572127
    1958         LogFlowFunc(("List inital: rc=%Rrc, srcRootAbs=%s, dstRootAbs=%s\n",
    1959                      vrc, strSrcRootAbs.c_str(), strDstRootAbs.c_str()));
    1960 
    1961         /* Calculated file copy flags for the current source spec. */
    1962         FileCopyFlag_T fFileCopyFlags = FileCopyFlag_None;
    1963 
    1964         /* Create the root directory. */
    19652128        if (pList->mSourceSpec.enmType == FsObjType_Directory)
    19662129        {
    1967             fCopyIntoExisting = RT_BOOL(pList->mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_CopyIntoExisting);
    1968             fFollowSymlinks   = RT_BOOL(pList->mSourceSpec.Type.Dir.fCopyFlags & DirectoryCopyFlag_FollowLinks);
    1969 
    19702130            LogFlowFunc(("Directory: fDirCopyFlags=%#x, fCopyIntoExisting=%RTbool, fFollowSymlinks=%RTbool\n",
    1971                          pList->mSourceSpec.Type.Dir.fCopyFlags, fCopyIntoExisting, fFollowSymlinks));
    1972 
    1973             /* If the directory on the guest already exists, append the name of the root source directory to it. */
    1974             switch (dstObjData.mType)
    1975             {
    1976                 case FsObjType_Directory:
    1977                 {
    1978                     if (fCopyIntoExisting)
     2131                         pList->mSourceSpec.fDirCopyFlags, fCopyIntoExisting, fFollowSymlinks));
     2132
     2133            if (fDstExists)
     2134            {
     2135                switch (dstObjData.mType)
     2136                {
     2137                    case FsObjType_Directory:
    19792138                    {
    1980                         /* Build the destination path on the guest. */
    1981                         strDstRootAbs += PATH_STYLE_SEP_STR(mSession->i_getGuestPathStyle()) + Utf8Str(RTPathFilename(strSrcRootAbs.c_str()));
     2139                        if (!fCopyIntoExisting)
     2140                        {
     2141                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2142                                                Utf8StrFmt(tr("Guest root directory \"%s\" already exists"),
     2143                                                           strDstRootAbs.c_str()));
     2144                            vrc = VERR_ALREADY_EXISTS;
     2145                        }
     2146                        break;
    19822147                    }
    1983                     else
     2148
     2149                    case FsObjType_File:
    19842150                    {
    19852151                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1986                                             Utf8StrFmt(tr("Guest directory \"%s\" already exists"),
     2152                                            Utf8StrFmt(tr("Destination \"%s\" on guest already exists and is a file"),
    19872153                                                       strDstRootAbs.c_str()));
    1988                         vrc = VERR_ALREADY_EXISTS;
     2154                        vrc = VERR_IS_A_FILE;
    19892155                    }
     2156
     2157                    case FsObjType_Symlink:
     2158                        /** @ŧodo Resolve symlinks? */
     2159                        break;
     2160
     2161                    default:
     2162                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2163                                            Utf8StrFmt(tr("Unknown object type (%#x) on guest for \"%s\""),
     2164                                                       dstObjData.mType, strDstRootAbs.c_str()));
     2165                        vrc = VERR_NOT_SUPPORTED;
     2166                        break;
     2167                }
     2168            }
     2169
     2170            if (RT_FAILURE(vrc))
     2171                break;
     2172
     2173            /* Clean up the final guest destination root path (for cleaning up mixed path separators). */
     2174            vrc = GuestPath::Translate(strDstRootAbs,
     2175                                       mSession->i_getGuestPathStyle() /* Source */, mSession->i_getGuestPathStyle() /* Dest */,
     2176                                       true /* fForce */);
     2177            if (RT_FAILURE(vrc))
     2178            {
     2179                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2180                                    Utf8StrFmt(tr("Translating guest destination root path '%s' failed: %Rrc"),
     2181                                               strDstRootAbs.c_str(), vrc));
     2182                break;
     2183            }
     2184
     2185            /* Make sure the destination root directory exists. */
     2186            if (pList->mSourceSpec.fDryRun == false)
     2187            {
     2188                vrc = directoryCreateOnGuest(strDstRootAbs, fDirMode, DirectoryCreateFlag_None,
     2189                                             fFollowSymlinks, fCopyIntoExisting);
     2190                if (RT_FAILURE(vrc))
    19902191                    break;
    1991                 }
    1992 
    1993                 case FsObjType_File:
    1994                     RT_FALL_THROUGH();
    1995                 case FsObjType_Symlink:
    1996                     /* Nothing to do. */
     2192            }
     2193
     2194            /* Walk the entries. */
     2195            FsEntries::const_iterator itEntry = pList->mVecEntries.begin();
     2196            while (   RT_SUCCESS(vrc)
     2197                   && itEntry != pList->mVecEntries.end())
     2198            {
     2199                FsEntry *pEntry = *itEntry;
     2200                AssertPtr(pEntry);
     2201
     2202                Utf8Str strSrcAbs = strSrcRootAbs;
     2203                Utf8Str strDstAbs = strDstRootAbs;
     2204
     2205                strSrcAbs += PATH_STYLE_SEP_STR(PATH_STYLE_NATIVE);
     2206                strSrcAbs += pEntry->strPath;
     2207
     2208                strDstAbs += PATH_STYLE_SEP_STR(mSession->i_getGuestPathStyle());
     2209                strDstAbs += pEntry->strPath;
     2210
     2211                /* Clean up the final host source path (for cleaning up mixed path separators). */
     2212                vrc = GuestPath::Translate(strSrcAbs,
     2213                                           PATH_STYLE_NATIVE /* Source */, PATH_STYLE_NATIVE /* Dest */,
     2214                                           true /* fForce */);
     2215                if (RT_FAILURE(vrc))
     2216                {
     2217                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2218                                        Utf8StrFmt(tr("Translating host source path '%s' from %s to %s failed: %Rrc"),
     2219                                                   strSrcAbs.c_str(),
     2220                                                   GuestBase::pathStyleToStr(PATH_STYLE_NATIVE),
     2221                                                   GuestBase::pathStyleToStr(PATH_STYLE_NATIVE), vrc));
    19972222                    break;
    1998 
    1999                 default:
     2223                }
     2224
     2225                /* Translate the final guest destination path. */
     2226                vrc = GuestPath::Translate(strDstAbs,
     2227                                           mSession->i_getGuestPathStyle() /* Source */, mSession->i_getGuestPathStyle() /* Dest */,
     2228                                           true /* fForce */);
     2229                if (RT_FAILURE(vrc))
     2230                {
    20002231                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    2001                                         Utf8StrFmt(tr("Unknown object type (%#x) on guest for \"%s\""),
    2002                                                    dstObjData.mType, strDstRootAbs.c_str()));
    2003                     vrc = VERR_NOT_SUPPORTED;
     2232                                        Utf8StrFmt(tr("Translating guest destination path '%s' from %s to %s failed: %Rrc"),
     2233                                                   strDstAbs.c_str(),
     2234                                                   GuestBase::pathStyleToStr(PATH_STYLE_NATIVE),
     2235                                                   GuestBase::pathStyleToStr(mSession->i_getGuestPathStyle()), vrc));
    20042236                    break;
    2005             }
    2006 
    2007             /* Make sure the destination root directory exists. */
    2008             if (   RT_SUCCESS(vrc)
    2009                 && pList->mSourceSpec.fDryRun == false)
    2010             {
    2011                 vrc = directoryCreateOnGuest(strDstRootAbs, DirectoryCreateFlag_None, fDirMode,
    2012                                              fFollowSymlinks, true /* fCanExist */);
    2013             }
    2014 
    2015             /* No tweaking of fFileCopyFlags needed here. */
     2237                }
     2238
     2239                mProgress->SetNextOperation(Bstr(strSrcAbs).raw(), 1);
     2240
     2241                switch (pEntry->fMode & RTFS_TYPE_MASK)
     2242                {
     2243                    case RTFS_TYPE_DIRECTORY:
     2244                    {
     2245                        LogRel2(("Guest Control: Copying directory '%s' from host to '%s' on guest ...\n", strSrcAbs.c_str(), strDstAbs.c_str()));
     2246                        if (!pList->mSourceSpec.fDryRun)
     2247                            vrc = directoryCreateOnGuest(strDstAbs, fDirMode, DirectoryCreateFlag_None,
     2248                                                         fFollowSymlinks, fCopyIntoExisting);
     2249                        break;
     2250                    }
     2251
     2252                    case RTFS_TYPE_FILE:
     2253                    {
     2254                        if (!pList->mSourceSpec.fDryRun)
     2255                            vrc = fileCopyToGuest(strSrcAbs, strDstAbs, pList->mSourceSpec.fFileCopyFlags);
     2256                        break;
     2257                    }
     2258
     2259                    default:
     2260                        LogRel2(("Guest Control: Warning: Host file system type 0x%x for '%s' is not supported, skipping\n",
     2261                                 pEntry->fMode & RTFS_TYPE_MASK, strSrcAbs.c_str()));
     2262                        break;
     2263                }
     2264
     2265                if (RT_FAILURE(vrc))
     2266                    break;
     2267
     2268                ++itEntry;
     2269            }
    20162270        }
    20172271        else if (pList->mSourceSpec.enmType == FsObjType_File)
    20182272        {
    2019             fCopyIntoExisting = !(pList->mSourceSpec.Type.File.fCopyFlags & FileCopyFlag_NoReplace);
    2020             fFollowSymlinks   = RT_BOOL(pList->mSourceSpec.Type.File.fCopyFlags & FileCopyFlag_FollowLinks);
    2021 
    20222273            LogFlowFunc(("File: fFileCopyFlags=%#x, fCopyIntoExisting=%RTbool, fFollowSymlinks=%RTbool\n",
    2023                          pList->mSourceSpec.Type.File.fCopyFlags, fCopyIntoExisting, fFollowSymlinks));
    2024 
    2025             fFileCopyFlags = pList->mSourceSpec.Type.File.fCopyFlags; /* Just use the flags directly from the spec. */
     2274                         pList->mSourceSpec.fFileCopyFlags, fCopyIntoExisting, fFollowSymlinks));
     2275
     2276            if (fDstExists)
     2277            {
     2278                switch (dstObjData.mType)
     2279                {
     2280                    case FsObjType_Directory:
     2281                    {
     2282                        if (!fCopyIntoExisting)
     2283                        {
     2284                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2285                                                Utf8StrFmt(tr("Destination \"%s\" on the guest already exists and is a directory"),
     2286                                                           strDstRootAbs.c_str()));
     2287                            vrc = VERR_IS_A_DIRECTORY;
     2288                            break;
     2289                        }
     2290
     2291                        /* Append the actual file name to the destination. */
     2292                        strDstRootAbs += PATH_STYLE_SEP_STR(mSession->i_getGuestPathStyle());
     2293                        strDstRootAbs += RTPathFilename(strSrcRootAbs.c_str());
     2294                        break;
     2295                    }
     2296
     2297                    case FsObjType_File:
     2298                    {
     2299                        if (!fCopyIntoExisting)
     2300                        {
     2301                            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2302                                                Utf8StrFmt(tr("Guest file \"%s\" already exists"), strDstRootAbs.c_str()));
     2303                            vrc = VERR_ALREADY_EXISTS;
     2304                        }
     2305                        break;
     2306                    }
     2307
     2308                    default:
     2309                    {
     2310                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2311                                            Utf8StrFmt(tr("Unsupported guest file system type (%#x) for \"%s\""),
     2312                                                       dstObjData.mType, strDstRootAbs.c_str()));
     2313                        vrc = VERR_NOT_SUPPORTED;
     2314                        break;
     2315                    }
     2316                }
     2317            }
     2318
     2319            /* Cleanup the destination path. */
     2320            vrc = GuestPath::Translate(strDstRootAbs, mSession->i_getGuestPathStyle() /* Source */,
     2321                                       mSession->i_getGuestPathStyle() /* Dest */, true /* fForce */);
     2322            if (RT_FAILURE(vrc))
     2323            {
     2324                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     2325                                    Utf8StrFmt(tr("Translating guest destination path '%s' from %s to %s failed: %Rrc"),
     2326                                               strDstRootAbs.c_str(), vrc));
     2327                break;
     2328            }
     2329
     2330            if (!pList->mSourceSpec.fDryRun)
     2331                vrc = fileCopyToGuest(strSrcRootAbs, strDstRootAbs, pList->mSourceSpec.fFileCopyFlags);
    20262332        }
    20272333        else
    20282334            AssertFailedStmt(vrc = VERR_NOT_SUPPORTED);
    2029 
    2030         LogFlowFunc(("List final: rc=%Rrc, srcRootAbs=%s, dstRootAbs=%s, fFileCopyFlags=%#x\n",
    2031                      vrc, strSrcRootAbs.c_str(), strDstRootAbs.c_str(), fFileCopyFlags));
    2032 
    2033         LogRel2(("Guest Control: Copying '%s' from host to '%s' on guest ...\n", strSrcRootAbs.c_str(), strDstRootAbs.c_str()));
    2034 
    2035         if (RT_FAILURE(vrc))
    2036             break;
    2037 
    2038         FsEntries::const_iterator itEntry = pList->mVecEntries.begin();
    2039         while (   RT_SUCCESS(vrc)
    2040                && itEntry != pList->mVecEntries.end())
    2041         {
    2042             FsEntry *pEntry = *itEntry;
    2043             AssertPtr(pEntry);
    2044 
    2045             Utf8Str strSrcAbs = strSrcRootAbs;
    2046             Utf8Str strDstAbs = strDstRootAbs;
    2047 
    2048             if (pList->mSourceSpec.enmType == FsObjType_Directory)
    2049             {
    2050                 strSrcAbs += PATH_STYLE_SEP_STR(PATH_STYLE_NATIVE);
    2051                 strSrcAbs += pEntry->strPath;
    2052             }
    2053 
    2054             /** @todo Handle stuff like "C:" for destination, where the destination will be the CWD for drive C. */
    2055             if (dstObjData.mType == FsObjType_Directory)
    2056             {
    2057                 strDstAbs += PATH_STYLE_SEP_STR(mSession->i_getGuestPathStyle());
    2058                 strDstAbs += pEntry->strPath;
    2059             }
    2060 
    2061             /* Translate the final source host path (for cleaning up mixed path separators). */
    2062             vrc = GuestPath::Translate(strSrcAbs, PATH_STYLE_NATIVE /* Source */, PATH_STYLE_NATIVE /* Dest */, true /* fForce */);
    2063             if (RT_FAILURE(vrc))
    2064                 break;
    2065 
    2066             /* Translate the final destination path from the host to a path compatible with the guest. */
    2067             vrc = GuestPath::Translate(strDstAbs, PATH_STYLE_NATIVE /* Source */, mSession->i_getGuestPathStyle() /* Dest */);
    2068             if (RT_FAILURE(vrc))
    2069                 break;
    2070 
    2071             mProgress->SetNextOperation(Bstr(strSrcAbs).raw(), 1);
    2072 
    2073             switch (pEntry->fMode & RTFS_TYPE_MASK)
    2074             {
    2075                 case RTFS_TYPE_DIRECTORY:
    2076                 {
    2077                     LogRel2(("Guest Control: Copying directory '%s' from host to '%s' on guest ...\n", strSrcAbs.c_str(), strDstAbs.c_str()));
    2078                     if (!pList->mSourceSpec.fDryRun)
    2079                         vrc = directoryCreateOnGuest(strDstAbs, DirectoryCreateFlag_None, fDirMode,
    2080                                                      fFollowSymlinks, fCopyIntoExisting);
    2081                     break;
    2082                 }
    2083 
    2084                 case RTFS_TYPE_FILE:
    2085                 {
    2086                     LogRel2(("Guest Control: Copying file '%s' from host to '%s' on guest ...\n", strSrcAbs.c_str(), strDstAbs.c_str()));
    2087                     if (!pList->mSourceSpec.fDryRun)
    2088                         vrc = fileCopyToGuest(strSrcAbs, strDstAbs, fFileCopyFlags);
    2089                     break;
    2090                 }
    2091 
    2092                 default:
    2093                     LogRel2(("Guest Control: Warning: Type 0x%x for '%s' is not supported, skipping\n",
    2094                              pEntry->fMode & RTFS_TYPE_MASK, strSrcAbs.c_str()));
    2095                     break;
    2096             }
    2097 
    2098             if (RT_FAILURE(vrc))
    2099                 break;
    2100 
    2101             ++itEntry;
    2102         }
    21032335
    21042336        if (RT_FAILURE(vrc))
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