VirtualBox

Changeset 92859 in vbox


Ignore:
Timestamp:
Dec 10, 2021 11:30:41 AM (3 years ago)
Author:
vboxsync
Message:

Guest Control/VBoxManage: Resolved @todos: Support more than one source in the copyfrom / copyto sub commands, use more POSIX-y syntax and let the wildcard matching be part of the calling process (i.e. via shell globbing).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r92822 r92859  
    261261        RTStrmPrintf(pStrm,
    262262                     "                              copyfrom [common-options]\n"
    263                      "                              [--follow] [-R|--recursive]\n"
     263                     "                              [-L|--dereference] [-R|--recursive]\n"
    264264                     "                              <guest-src0> [guest-src1 [...]] <host-dst>\n"
    265265                     "\n"
    266266                     "                              copyfrom [common-options]\n"
    267                      "                              [--follow] [-R|--recursive]\n"
    268                      "                              [--target-directory <host-dst-dir>]\n"
     267                     "                              [-L|--dereference] [-R|--recursive]\n"
     268                     "                              [-t|--target-directory <host-dst-dir>]\n"
    269269                     "                              <guest-src0> [guest-src1 [...]]\n"
    270270                     "\n");
     
    272272        RTStrmPrintf(pStrm,
    273273                     "                              copyto [common-options]\n"
    274                      "                              [--follow] [-R|--recursive]\n"
     274                     "                              [-L|--dereference] [-R|--recursive]\n"
    275275                     "                              <host-src0> [host-src1 [...]] <guest-dst>\n"
    276276                     "\n"
    277277                     "                              copyto [common-options]\n"
    278                      "                              [--follow] [-R|--recursive]\n"
    279                      "                              [--target-directory <guest-dst>]\n"
     278                     "                              [-L|--dereference] [-R|--recursive]\n"
     279                     "                              [-t|--target-directory <guest-dst>]\n"
    280280                     "                              <host-src0> [host-src1 [...]]\n"
    281281                     "\n");
     
    17241724    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
    17251725
    1726     /** @todo r=bird: This command isn't very unix friendly in general. mkdir
    1727      * is much better (partly because it is much simpler of course).  The main
    1728      * arguments against this is that (1) all but two options conflicts with
    1729      * what 'man cp' tells me on a GNU/Linux system, (2) wildchar matching is
    1730      * done windows CMD style (though not in a 100% compatible way), and (3)
    1731      * that only one source is allowed - efficiently sabotaging default
    1732      * wildcard expansion by a unix shell.  The best solution here would be
    1733      * two different variant, one windowsy (xcopy) and one unixy (gnu cp). */
    1734 
    17351726    /*
    17361727     * IGuest::CopyToGuest is kept as simple as possible to let the developer choose
     
    17381729     * does in here.
    17391730     */
    1740     enum GETOPTDEF_COPY
    1741     {
    1742         GETOPTDEF_COPY_FOLLOW = 1000,
    1743         GETOPTDEF_COPY_TARGETDIR
    1744     };
    17451731    static const RTGETOPTDEF s_aOptions[] =
    17461732    {
    17471733        GCTLCMD_COMMON_OPTION_DEFS()
    1748         { "--follow",              GETOPTDEF_COPY_FOLLOW,           RTGETOPT_REQ_NOTHING },
    1749         { "--recursive",           'R',                             RTGETOPT_REQ_NOTHING },
    1750         { "--target-directory",    GETOPTDEF_COPY_TARGETDIR,        RTGETOPT_REQ_STRING  }
     1734        { "--follow",              'L',     RTGETOPT_REQ_NOTHING }, /* Kept for backwards-compatibility (VBox < 7.0). */
     1735        { "--dereference",         'L',     RTGETOPT_REQ_NOTHING },
     1736        { "--recursive",           'R',     RTGETOPT_REQ_NOTHING },
     1737        { "--target-directory",    't',     RTGETOPT_REQ_STRING  }
    17511738    };
    17521739
     
    17711758            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
    17721759
    1773             case GETOPTDEF_COPY_FOLLOW:
     1760            case 'L':
     1761                if (!RTStrICmp(ValueUnion.pDef->pszLong, "--follow"))
     1762                    RTMsgWarning("--follow is deprecated; use --dereference instead.");
    17741763                fFollow = true;
    17751764                break;
    17761765
    1777             case 'R': /* Recursive processing */
     1766            case 'R':
    17781767                fRecursive = true;
    17791768                break;
    17801769
    1781             case GETOPTDEF_COPY_TARGETDIR:
     1770            case 't':
    17821771                pszDst = ValueUnion.psz;
    17831772                fDstMustBeDir = true;
     
    18281817    }
    18291818
    1830     HRESULT           rc = S_OK;
    1831     ComPtr<IProgress> pProgress;
    1832 /** @todo r=bird: This codes does nothing to handle the case where there are
    1833  * multiple sources.  You need to do serveral thing before thats handled
    1834  * correctly.  For starters the progress object handling needs to be moved
    1835  * inside the loop.  Next you need to check what the destination is, because you
    1836  * can only copy multiple source files/directories to another directory.  You
    1837  * actually need to check whether the target exists and is a directory
    1838  * regardless of you have 1 or 10 source files/dirs.
    1839  *
    1840  * Btw. the original approach to error handling here was APPALING.  If some file
    1841  * couldn't be stat'ed or if it was a file/directory, you only spat out messages
    1842  * in verbose mode and never set the status code.
    1843  *
    1844  * The handling of the wildcard filtering expressions in sources was also just
    1845  * skipped.   I've corrected this, but you still need to make up your mind wrt
    1846  * wildcards or not.
    1847  *
    1848  * Update: I've kicked out the whole SourceFileEntry/vecSources stuff as we can
    1849  *         use argv directly without any unnecessary copying.  You just have to
    1850  *         look for the wildcards inside this loop instead.
    1851  */
    1852     NOREF(fDstMustBeDir);
    1853     if (cSources != 1)
    1854         return RTMsgErrorExitFailure(GuestCtrl::tr("Only one source file or directory at the moment."));
     1819    HRESULT rc = S_OK;
     1820
     1821    bool fDstIsDir = false;
     1822
     1823    if (!fHostToGuest)
     1824    {
     1825        RTFSOBJINFO ObjInfo;
     1826        vrc = RTPathQueryInfo(szAbsDst, &ObjInfo, RTFSOBJATTRADD_NOTHING);
     1827        if (RT_FAILURE(vrc))
     1828            return RTMsgErrorExitFailure(GuestCtrl::tr("RTPathQueryInfo failed on '%s': %Rrc"), szAbsDst, vrc);
     1829        fDstIsDir = RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode);
     1830    }
     1831    else
     1832    {
     1833        BOOL fDirExists = FALSE;
     1834        rc = pCtx->pGuestSession->DirectoryExists(Bstr(pszDst).raw(), TRUE /* fFollowSymlinks */, &fDirExists);
     1835        if (SUCCEEDED(rc))
     1836            fDstIsDir = RT_BOOL(fDirExists);
     1837    }
     1838
     1839    /* If multiple sources are specified, the destination must be a directory. */
     1840    fDstMustBeDir = cSources > 1;
     1841
     1842    /* If destination must be a directory, check this first before everything else. */
     1843    if (    fDstMustBeDir
     1844        && !fDstIsDir)
     1845    {
     1846        return RTMsgErrorExitFailure(GuestCtrl::tr("Destination must be a directory!"));
     1847    }
     1848
    18551849    for (size_t iSrc = 0; iSrc < cSources; iSrc++)
    18561850    {
    1857         const char *pszSource = papszSources[iSrc];
    1858 
    1859         /* Check if the source contains any wilecards in the last component, if so we
    1860            don't know how to deal with it yet and refuse. */
    1861         const char *pszSrcFinalComp = RTPathFilename(pszSource);
    1862         if (pszSrcFinalComp && strpbrk(pszSrcFinalComp, "*?"))
    1863             rcExit = RTMsgErrorExitFailure(GuestCtrl::tr("Skipping '%s' because wildcard expansion isn't implemented yet\n"),
    1864                                            pszSource);
    1865         else if (fHostToGuest)
     1851        /*
     1852         * Note: Having a dedicated progress object on every single source being copied can be very slow.
     1853         *       We implement IGuestSession::Copy[From|To]Guest() since quite a while which does most of the below
     1854         *       under the hood in Main using a multi-staged progress object. However, leave this like it is for now
     1855         *       to (also) have a different method of API testing.
     1856         */
     1857        ComPtr<IProgress> pProgress;
     1858        const char       *pszSource = papszSources[iSrc];
     1859
     1860        /* Note: Wildcards have to be processed by the calling process (i.e. via globbing, if available). */
     1861
     1862        if (fHostToGuest)
    18661863        {
    18671864            /*
     
    18811878                            RTPrintf(GuestCtrl::tr("File '%s' -> '%s'\n"), szAbsSrc, pszDst);
    18821879
    1883                         SafeArray<FileCopyFlag_T> copyFlags;
     1880                        SafeArray<FileCopyFlag_T> aCopyFlags;
    18841881                        rc = pCtx->pGuestSession->FileCopyToGuest(Bstr(szAbsSrc).raw(), Bstr(pszDst).raw(),
    1885                                                                   ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam());
     1882                                                                  ComSafeArrayAsInParam(aCopyFlags), pProgress.asOutParam());
    18861883                    }
    18871884                    else if (RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
     
    19571954                rcExit = RTMsgErrorExitFailure(GuestCtrl::tr("FsObjQueryInfo failed on '%s': %Rhrc"), pszSource, rc);
    19581955        }
    1959     }
    1960 
    1961     if (FAILED(rc))
    1962     {
    1963         vrc = gctlPrintError(pCtx->pGuestSession, COM_IIDOF(IGuestSession));
    1964     }
    1965     else if (pProgress.isNotNull())
    1966     {
    1967         if (pCtx->cVerbose)
    1968             rc = showProgress(pProgress);
    1969         else
    1970             rc = pProgress->WaitForCompletion(-1 /* No timeout */);
    1971         if (SUCCEEDED(rc))
    1972             CHECK_PROGRESS_ERROR(pProgress, (GuestCtrl::tr("File copy failed")));
    1973         vrc = gctlPrintProgressError(pProgress);
    1974     }
     1956
     1957        if (FAILED(rc))
     1958        {
     1959            vrc = gctlPrintError(pCtx->pGuestSession, COM_IIDOF(IGuestSession));
     1960        }
     1961        else if (pProgress.isNotNull())
     1962        {
     1963            if (pCtx->cVerbose)
     1964                rc = showProgress(pProgress);
     1965            else
     1966                rc = pProgress->WaitForCompletion(-1 /* No timeout */);
     1967            if (SUCCEEDED(rc))
     1968                CHECK_PROGRESS_ERROR(pProgress, (GuestCtrl::tr("File copy failed")));
     1969            vrc = gctlPrintProgressError(pProgress);
     1970        }
     1971
     1972        /* Keep going. */
     1973    }
     1974
    19751975    if (RT_FAILURE(vrc))
    19761976        rcExit = RTEXITCODE_FAILURE;
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