VirtualBox

Changeset 36609 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
Apr 7, 2011 9:20:29 AM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
71056
Message:

VBoxManage/GuestCtrl: Added multiple source handling for copyto and made it more similar to cp.

File:
1 edited

Legend:

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

    r36227 r36609  
    108108    GETOPTDEF_EXEC_WAITFORSTDOUT,
    109109    GETOPTDEF_EXEC_WAITFORSTDERR
     110};
     111
     112enum GETOPTDEF_COPYTO
     113{
     114    GETOPTDEF_COPYTO_DRYRUN = 1000,
     115    GETOPTDEF_COPYTO_FOLLOW,
     116    GETOPTDEF_COPYTO_PASSWORD,
     117    GETOPTDEF_COPYTO_TARGETDIR,
     118    GETOPTDEF_COPYTO_USERNAME
    110119};
    111120
     
    488497            case VINF_GETOPT_NOT_OPTION:
    489498            {
    490 #if 0 /** @todo r=bird: enable this when the argv[0] issue has been addressed. */
    491499                if (args.size() == 0 && Utf8Cmd.isEmpty())
    492500                    Utf8Cmd = ValueUnion.psz;
    493501                args.push_back(Bstr(ValueUnion.psz).raw());
    494 #else
    495                 if (Utf8Cmd.isEmpty())
    496                 {
    497                     Utf8Cmd = ValueUnion.psz;
    498                     if (Utf8Cmd.isEmpty())
    499                         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The first argument cannot be empty yet, wait for 4.1.0");
    500                 }
    501                 else
    502                     args.push_back(Bstr(ValueUnion.psz).raw());
    503 #endif
    504502                break;
    505503            }
     
    10061004                if (RT_SUCCESS(rc))
    10071005                {
    1008                     RTListInit(pList);
    10091006                    rc = ctrlDirectoryEntryAppend(pszSourceAbs, pszDestAbs, pList);
    10101007                    *pcObjects = 1;
     
    10671064                if (RT_SUCCESS(rc))
    10681065                {
    1069                     RTListInit(pList);
    10701066                    rc = ctrlCopyDirectoryRead(pszSourceAbsRoot, NULL /* Sub directory */,
    10711067                                               pszFilter, pszDestAbs,
     
    11401136     * wildcard expansion by a unix shell.  The best solution here would be
    11411137     * two different variant, one windowsy (xcopy) and one unixy (gnu cp). */
    1142     /** @todo r=bird: Why isn't IGuest::CopyToGuest powerful enough to do
    1143      *        all this recursive copying? */
     1138
     1139    /*
     1140     * IGuest::CopyToGuest is kept as simple as possible to let the developer choose
     1141     * what and how to implement the file enumeration/recursive lookup, like VBoxManage
     1142     * does in here.
     1143     */
    11441144
    11451145    static const RTGETOPTDEF s_aOptions[] =
    11461146    {
    1147         { "--dryrun",              'd',         RTGETOPT_REQ_NOTHING }, /**< @todo r=bird: '-d' incompatible with GNU cp.  */
    1148         { "--follow",              'F',         RTGETOPT_REQ_NOTHING }, /**< @todo r=bird: This isn't a GNU cp option. This is instead spread over several options.  */
    1149         { "--password",            'p',         RTGETOPT_REQ_STRING  }, /**< @todo r=bird: Just drop these short options since (BSD, GNU, ++) cp uses '-p' to indicate that ownership, timestamp and other stuff should be preserved.  Other file commands probably use '-p' as well. */
    1150         { "--recursive",           'R',         RTGETOPT_REQ_NOTHING }, /**< @todo r=bird: Most cp implementations treats '-r' as an alias for '-R'. */
    1151         { "--username",            'u',         RTGETOPT_REQ_STRING  }, /**< @todo r=bird: Just drop these short options since GNU cp uses '-u' to indicate update-only (as does 4nt).  Other file commands probably uses '-u' as well. */
    1152         { "--verbose",             'v',         RTGETOPT_REQ_NOTHING }
     1147        { "--dryrun",              GETOPTDEF_COPYTO_DRYRUN,         RTGETOPT_REQ_NOTHING },
     1148        { "--follow",              GETOPTDEF_COPYTO_FOLLOW,         RTGETOPT_REQ_NOTHING },
     1149        { "--password",            GETOPTDEF_COPYTO_PASSWORD,       RTGETOPT_REQ_STRING  },
     1150        { "--recursive",           'R',                             RTGETOPT_REQ_NOTHING },
     1151        { "--target-directory",    GETOPTDEF_COPYTO_TARGETDIR,      RTGETOPT_REQ_STRING  },
     1152        { "--username",            GETOPTDEF_COPYTO_USERNAME,       RTGETOPT_REQ_STRING  },
     1153        { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
    11531154    };
    11541155
     
    11561157    RTGETOPTUNION ValueUnion;
    11571158    RTGETOPTSTATE GetState;
    1158     RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
     1159    RTGetOptInit(&GetState, pArg->argc, pArg->argv,
     1160                 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    11591161
    11601162    Utf8Str Utf8Source;
     
    11671169    bool fDryRun = false;
    11681170
     1171    RTLISTNODE listSources;
     1172    uint32_t cSources = 0;
     1173    RTListInit(&listSources);
     1174
    11691175    int vrc = VINF_SUCCESS;
    1170     uint32_t idxNonOption = 0;
    11711176    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
    11721177    {
     
    11741179        switch (ch)
    11751180        {
    1176             case 'd': /* Dry run */
     1181            case GETOPTDEF_COPYTO_DRYRUN:
    11771182                fDryRun = true;
    11781183                break;
    11791184
    1180             case 'F': /* Follow symlinks */
     1185            case GETOPTDEF_COPYTO_FOLLOW:
    11811186                fFlags |= CopyFileFlag_FollowLinks;
    11821187                break;
    11831188
    1184             case 'p': /* Password */
     1189            case GETOPTDEF_COPYTO_PASSWORD:
    11851190                Utf8Password = ValueUnion.psz;
    11861191                break;
     
    11901195                break;
    11911196
    1192             case 'u': /* User name */
     1197            case GETOPTDEF_COPYTO_TARGETDIR:
     1198                Utf8Dest = ValueUnion.psz;
     1199                break;
     1200
     1201            case GETOPTDEF_COPYTO_USERNAME:
    11931202                Utf8UserName = ValueUnion.psz;
    11941203                break;
     
    12001209            case VINF_GETOPT_NOT_OPTION:
    12011210            {
    1202                 /* Get the actual source + destination. */
    1203                 switch (idxNonOption)
     1211                /* Last argument and no destination specified with
     1212                 * --target-directory yet? Then use the current argument
     1213                 * as destination. */
     1214                if (   pArg->argc == GetState.iNext
     1215                    && Utf8Dest.isEmpty())
    12041216                {
    1205                     case 0:
    1206                         Utf8Source = ValueUnion.psz;
    1207                         break;
    1208 
    1209                     case 1:
    1210                         Utf8Dest = ValueUnion.psz;
    1211                         break;
    1212 
    1213                     /* @todo r=bird: VBoxManage guestcontrol execute <VMName> copyto hostfile.1 hostfile.2 hostfile.3 guestdir/
    1214                      * A better way to implement this would be to tell RTGetOptInit to sort the argument, so
    1215                      * that when VINF_GETOPT_NOT_OPTION is returned, the remainder of pArg->argv are all arguments. */
    1216 
    1217                     default:
    1218                         return errorSyntax(USAGE_GUESTCONTROL, "Too many parameters specified, only source and destination allowed!");
     1217                    Utf8Dest = ValueUnion.psz;
    12191218                }
    1220                 idxNonOption++;
    1221                 if (idxNonOption == UINT32_MAX)
    1222                     return errorSyntax(USAGE_GUESTCONTROL, "Too many files specified!");
     1219                else
     1220                {
     1221                    int vrc = ctrlDirectoryEntryAppend(ValueUnion.psz,      /* Source */
     1222                                                       NULL,                /* No destination given */
     1223                                                       &listSources);
     1224                    if (RT_SUCCESS(vrc))
     1225                    {
     1226                        cSources++;
     1227                        if (cSources == UINT32_MAX)
     1228                            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many sources specified! Aborting.");
     1229                    }
     1230                    else
     1231                        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to append source: %Rrc", vrc);
     1232                }
    12231233                break;
    12241234            }
     
    12291239    }
    12301240
    1231     if (Utf8Source.isEmpty())
     1241    if (!cSources)
    12321242        return errorSyntax(USAGE_GUESTCONTROL,
    1233                            "No source specified!");
     1243                           "No source(s) specified!");
    12341244
    12351245    if (Utf8Dest.isEmpty())
     
    12531263
    12541264    RTLISTNODE listToCopy;
    1255     uint32_t cObjects = 0;
    1256     vrc = ctrlCopyInit(Utf8Source.c_str(), Utf8Dest.c_str(), fFlags,
    1257                        &cObjects, &listToCopy);
    1258     if (RT_FAILURE(vrc))
    1259     {
    1260         switch (vrc)
    1261         {
    1262             case VERR_NOT_FOUND:
    1263                 RTMsgError("No files to copy found!\n");
    1264                 break;
    1265 
    1266             case VERR_FILE_NOT_FOUND:
    1267                 RTMsgError("Source path \"%s\" not found!\n", Utf8Source.c_str());
    1268                 break;
    1269 
    1270             default:
    1271                 RTMsgError("Failed to initialize, rc=%Rrc\n", vrc);
    1272                 break;
    1273         }
    1274     }
    1275     else
     1265    RTListInit(&listToCopy);
     1266    uint32_t cTotalObjects = 0;
     1267
     1268    PDIRECTORYENTRY pNodeSource;
     1269    RTListForEach(&listSources, pNodeSource, DIRECTORYENTRY, Node)
     1270    {
     1271        uint32_t cObjects = 0;
     1272        vrc = ctrlCopyInit(pNodeSource->pszSourcePath, Utf8Dest.c_str(), fFlags,
     1273                           &cObjects, &listToCopy);
     1274        if (RT_FAILURE(vrc))
     1275        {
     1276            switch (vrc)
     1277            {
     1278                case VERR_NOT_FOUND:
     1279                    /* Not fatal, just continue to the next source entry (if available). */
     1280                    continue;
     1281
     1282                case VERR_FILE_NOT_FOUND:
     1283                    RTMsgError("Source path \"%s\" not found!\n", Utf8Source.c_str());
     1284                    break;
     1285
     1286                default:
     1287                    RTMsgError("Failed to initialize, rc=%Rrc\n", vrc);
     1288                    break;
     1289            }
     1290        }
     1291        else if (fVerbose)
     1292        {
     1293            RTPrintf("Source \"%s\" has %ld elements to copy\n",
     1294                     pNodeSource->pszSourcePath, cObjects);
     1295        }
     1296        cTotalObjects += cObjects;
     1297    }
     1298
     1299    if (fVerbose && cTotalObjects)
     1300        RTPrintf("Total %ld elements to copy to \"%s\"\n",
     1301                 cTotalObjects, Utf8Dest.c_str());
     1302
     1303    if (cTotalObjects)
    12761304    {
    12771305        PDIRECTORYENTRY pNode;
    1278         if (RT_SUCCESS(vrc))
     1306        uint32_t uCurObject = 1;
     1307
     1308        RTListForEach(&listToCopy, pNode, DIRECTORYENTRY, Node)
    12791309        {
    12801310            if (fVerbose)
    1281             {
    1282                 if (fCopyRecursive)
    1283                     RTPrintf("Recursively copying \"%s\" to \"%s\" (%u file(s)) ...\n",
    1284                              Utf8Source.c_str(), Utf8Dest.c_str(), cObjects);
    1285                 else
    1286                     RTPrintf("Copying \"%s\" to \"%s\" (%u file(s)) ...\n",
    1287                              Utf8Source.c_str(), Utf8Dest.c_str(), cObjects);
    1288             }
    1289 
    1290             uint32_t iObject = 1;
    1291             RTListForEach(&listToCopy, pNode, DIRECTORYENTRY, Node)
    1292             {
    1293                 if (!fDryRun)
    1294                 {
    1295                     if (fVerbose)
    1296                         RTPrintf("Copying \"%s\" to \"%s\" (%u/%u) ...\n",
    1297                                  pNode->pszSourcePath, pNode->pszDestPath, iObject, cObjects);
    1298                     /* Finally copy the desired file (if no dry run selected). */
    1299                     if (!fDryRun)
    1300                         vrc = ctrlCopyFileToGuest(guest, fVerbose, pNode->pszSourcePath, pNode->pszDestPath,
    1301                                                   Utf8UserName.c_str(), Utf8Password.c_str(), fFlags);
    1302                 }
    1303                 if (RT_FAILURE(vrc))
    1304                     break;
    1305                 iObject++;
    1306             }
    1307             if (RT_SUCCESS(vrc) && fVerbose)
    1308                 RTPrintf("Copy operation successful!\n");
    1309         }
    1310         ctrlDirectoryListDestroy(&listToCopy);
    1311     }
     1311                RTPrintf("Copying \"%s\" to \"%s\" (%u/%u) ...\n",
     1312                         pNode->pszSourcePath, pNode->pszDestPath, uCurObject, cTotalObjects);
     1313            /* Finally copy the desired file (if no dry run selected). */
     1314            if (!fDryRun)
     1315                vrc = ctrlCopyFileToGuest(guest, fVerbose, pNode->pszSourcePath, pNode->pszDestPath,
     1316                                          Utf8UserName.c_str(), Utf8Password.c_str(), fFlags);
     1317            if (RT_FAILURE(vrc))
     1318                break;
     1319            uCurObject++;
     1320        }
     1321        Assert(cTotalObjects == uCurObject - 1);
     1322
     1323        if (RT_SUCCESS(vrc) && fVerbose)
     1324            RTPrintf("Copy operation successful!\n");
     1325    }
     1326
     1327    ctrlDirectoryListDestroy(&listToCopy);
     1328    ctrlDirectoryListDestroy(&listSources);
    13121329
    13131330    if (RT_FAILURE(vrc))
     
    13381355    RTGETOPTUNION ValueUnion;
    13391356    RTGETOPTSTATE GetState;
    1340     RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
     1357    RTGetOptInit(&GetState, pArg->argc, pArg->argv,
     1358                 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    13411359
    13421360    Utf8Str Utf8UserName;
    13431361    Utf8Str Utf8Password;
    13441362    uint32_t fFlags = CreateDirectoryFlag_None;
    1345     uint32_t fDirMode = 0; /* 0 == default mode, right? */
     1363    uint32_t fDirMode = 0; /* Default mode. */
    13461364    bool fVerbose = false;
    13471365
     
    13791397            case VINF_GETOPT_NOT_OPTION:
    13801398            {
    1381 /** @todo r=bird: Simplify by letting RTGetOptInit sort the argv, just like
    1382  *        for cp. */
    13831399                int vrc = ctrlDirectoryEntryAppend(NULL,              /* No source given */
    13841400                                                   ValueUnion.psz,    /* Destination */
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