VirtualBox

Changeset 37403 in vbox


Ignore:
Timestamp:
Jun 10, 2011 8:05:58 AM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
72200
Message:

VBoxService/Toolbox: Implemented ls tool.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp

    r37340 r37403  
    4646#define CAT_OPT_NO_CONTENT_INDEXED              1000
    4747
     48#define LS_OPT_MACHINE_READABLE                 1000
     49
    4850/* Enable the following define to be able to debug/invoke the toolbox
    4951 * commandos directly from command line, e.g. VBoxService vbox_cat [args] */
     
    6466} VBOXSERVICETOOLBOXPATHENTRY, *PVBOXSERVICETOOLBOXPATHENTRY;
    6567
     68typedef struct VBOXSERVICETOOLBOXDIRENTRY
     69{
     70    /** Our node. */
     71    RTLISTNODE   Node;
     72    /** The actual entry. */
     73    RTDIRENTRYEX dirEntry;
     74} VBOXSERVICETOOLBOXDIRENTRY, *PVBOXSERVICETOOLBOXDIRENTRY;
     75
    6676
    6777/**
     
    7282    RTPrintf("Toolbox Usage:\n"
    7383             "cat [FILE] - Concatenate FILE(s), or standard input, to standard output.\n"
     84             "\n"
     85             /** @todo Document options! */
     86             "ls [OPTION]... FILE... - List information about the FILEs (the current directory by default).\n"
    7487             "\n"
    7588             /** @todo Document options! */
     
    216229
    217230/**
     231 * Main function for tool "vbox_cat".
     232 *
     233 * @return  RTEXITCODE.
     234 * @param   argc                    Number of arguments.
     235 * @param   argv                    Pointer to argument array.
     236 */
     237static RTEXITCODE VBoxServiceToolboxCat(int argc, char **argv)
     238{
     239    static const RTGETOPTDEF s_aOptions[] =
     240    {
     241        /* Sorted by short ops. */
     242        { "--show-all",            'a',                         RTGETOPT_REQ_NOTHING },
     243        { "--number-nonblank",     'b',                         RTGETOPT_REQ_NOTHING},
     244        { NULL,                    'e',                         RTGETOPT_REQ_NOTHING},
     245        { NULL,                    'E',                         RTGETOPT_REQ_NOTHING},
     246        { "--flags",               'f',                         RTGETOPT_REQ_STRING},
     247        { "--no-content-indexed",  CAT_OPT_NO_CONTENT_INDEXED,  RTGETOPT_REQ_NOTHING},
     248        { "--number",              'n',                         RTGETOPT_REQ_NOTHING},
     249        { "--output",              'o',                         RTGETOPT_REQ_STRING},
     250        { "--squeeze-blank",       's',                         RTGETOPT_REQ_NOTHING},
     251        { NULL,                    't',                         RTGETOPT_REQ_NOTHING},
     252        { "--show-tabs",           'T',                         RTGETOPT_REQ_NOTHING},
     253        { NULL,                    'u',                         RTGETOPT_REQ_NOTHING},
     254        { "--show-noneprinting",   'v',                         RTGETOPT_REQ_NOTHING}
     255    };
     256
     257    int ch;
     258    RTGETOPTUNION ValueUnion;
     259    RTGETOPTSTATE GetState;
     260
     261    RTGetOptInit(&GetState, argc, argv,
     262                 s_aOptions, RT_ELEMENTS(s_aOptions),
     263                 /* Index of argv to start with. */
     264#ifdef VBOXSERVICE_TOOLBOX_DEBUG
     265                 2,
     266#else
     267                 1,
     268#endif
     269                 0);
     270
     271    int rc = VINF_SUCCESS;
     272    bool fUsageOK = true;
     273
     274    char szOutput[RTPATH_MAX] = { 0 };
     275    RTFILE hOutput = NIL_RTFILE;
     276    uint32_t fFlags = RTFILE_O_CREATE_REPLACE /* Output file flags. */
     277                      | RTFILE_O_WRITE
     278                      | RTFILE_O_DENY_WRITE;
     279
     280    /* Init directory list. */
     281    RTLISTNODE inputList;
     282    RTListInit(&inputList);
     283
     284    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     285              && RT_SUCCESS(rc))
     286    {
     287        /* For options that require an argument, ValueUnion has received the value. */
     288        switch (ch)
     289        {
     290            case 'a':
     291            case 'b':
     292            case 'e':
     293            case 'E':
     294            case 'n':
     295            case 's':
     296            case 't':
     297            case 'T':
     298            case 'v':
     299                RTMsgError("cat: Sorry, option '%s' is not implemented yet!\n",
     300                           ValueUnion.pDef->pszLong);
     301                rc = VERR_INVALID_PARAMETER;
     302                break;
     303
     304            case 'h':
     305                VBoxServiceToolboxShowUsage();
     306                return RTEXITCODE_SUCCESS;
     307
     308            case 'o':
     309                if (!RTStrPrintf(szOutput, sizeof(szOutput), ValueUnion.psz))
     310                    rc = VERR_NO_MEMORY;
     311                break;
     312
     313            case 'u':
     314                /* Ignored. */
     315                break;
     316
     317            case 'V':
     318                VBoxServiceToolboxShowVersion();
     319                return RTEXITCODE_SUCCESS;
     320
     321            case CAT_OPT_NO_CONTENT_INDEXED:
     322                fFlags |= RTFILE_O_NOT_CONTENT_INDEXED;
     323                break;
     324
     325            case VINF_GETOPT_NOT_OPTION:
     326                {
     327                    /* Add file(s) to buffer. This enables processing multiple paths
     328                     * at once.
     329                     *
     330                     * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
     331                     * processing this loop it's safe to immediately exit on syntax errors
     332                     * or showing the help text (see above). */
     333                    rc = VBoxServiceToolboxPathBufAddPathEntry(&inputList, ValueUnion.psz);
     334                    break;
     335                }
     336
     337            default:
     338                return RTGetOptPrintError(ch, &ValueUnion);
     339        }
     340    }
     341
     342    if (RT_SUCCESS(rc))
     343    {
     344        if (strlen(szOutput))
     345        {
     346            rc = RTFileOpen(&hOutput, szOutput, fFlags);
     347            if (RT_FAILURE(rc))
     348                RTMsgError("cat: Could not create output file '%s', rc=%Rrc\n",
     349                           szOutput, rc);
     350        }
     351
     352        if (RT_SUCCESS(rc))
     353        {
     354            /* Process each input file. */
     355            PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
     356            RTFILE hInput = NIL_RTFILE;
     357            RTListForEach(&inputList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
     358            {
     359                rc = RTFileOpen(&hInput, pNodeIt->pszName,
     360                                RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     361                if (RT_SUCCESS(rc))
     362                {
     363                    rc = VBoxServiceToolboxCatOutput(hInput, hOutput);
     364                    RTFileClose(hInput);
     365                }
     366                else
     367                {
     368                    PCRTSTATUSMSG pMsg = RTErrGet(rc);
     369                    if (pMsg)
     370                        RTMsgError("cat: Could not open input file '%s': %s\n",
     371                                   pNodeIt->pszName, pMsg->pszMsgFull);
     372                    else
     373                        RTMsgError("cat: Could not open input file '%s', rc=%Rrc\n", pNodeIt->pszName, rc);
     374                }
     375
     376                if (RT_FAILURE(rc))
     377                    break;
     378            }
     379
     380            /* If not input files were defined, process stdin. */
     381            if (RTListNodeIsFirst(&inputList, &inputList))
     382                rc = VBoxServiceToolboxCatOutput(hInput, hOutput);
     383        }
     384    }
     385
     386    if (hOutput != NIL_RTFILE)
     387        RTFileClose(hOutput);
     388    VBoxServiceToolboxPathBufDestroy(&inputList);
     389
     390    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     391}
     392
     393/**
     394 * Helper routine for ls tool doing the actual parsing and output of
     395 * a specified directory.
     396 *
     397 * @return  IPRT status code.
     398 * @param   pszDir                  Directory (path) to ouptut.
     399 * @param   fRecursive              Flag indicating whether recursive directory handling
     400 *                                  is wanted or not.
     401 * @param   fLong                   Flag indicating whether long output is required or not.
     402 * @param   fParseable              Flag indicating whether machine parseable output
     403 *                                  is required or not
     404 */
     405static int VBoxServiceToolboxLsOutput(const char *pszDir,
     406                                      bool fRecursive, bool fLong, bool fParseable)
     407{
     408    AssertPtrReturn(pszDir, VERR_INVALID_PARAMETER);
     409
     410    if (fParseable)
     411        RTPrintf("dname=%s%c", pszDir, 0);
     412
     413    char szPathAbs[RTPATH_MAX + 1];
     414    int rc = RTPathAbs(pszDir, szPathAbs, sizeof(szPathAbs));
     415    if (RT_FAILURE(rc))
     416    {
     417        RTMsgError("ls: Failed to retrieve absolute path of '%s', rc=%Rrc\n", pszDir, rc);
     418        return rc;
     419    }
     420
     421    PRTDIR pDir;
     422    rc = RTDirOpen(&pDir, szPathAbs);
     423    if (RT_FAILURE(rc))
     424    {
     425        RTMsgError("ls: Failed to open '%s', rc=%Rrc\n", szPathAbs, rc);
     426        return rc;
     427    }
     428
     429    RTLISTNODE dirList;
     430    RTListInit(&dirList);
     431
     432    /* To prevent races we need to read in the directory entries once
     433     * and process them afterwards: First loop is displaying the current
     434     * directory's content and second loop is diving deeper into
     435     * sub directories (if wanted). */
     436    for (;RT_SUCCESS(rc);)
     437    {
     438        RTDIRENTRYEX DirEntry;
     439        rc = RTDirReadEx(pDir, &DirEntry, NULL, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
     440        if (RT_SUCCESS(rc))
     441        {
     442            PVBOXSERVICETOOLBOXDIRENTRY pNode = (PVBOXSERVICETOOLBOXDIRENTRY)RTMemAlloc(sizeof(VBOXSERVICETOOLBOXDIRENTRY));
     443            if (pNode)
     444            {
     445                memcpy(&pNode->dirEntry, &DirEntry, sizeof(RTDIRENTRYEX));
     446                /*rc =*/ RTListAppend(&dirList, &pNode->Node);
     447            }
     448            else
     449                rc = VERR_NO_MEMORY;
     450        }
     451    }
     452
     453    if (rc == VERR_NO_MORE_FILES)
     454        rc = VINF_SUCCESS;
     455
     456    int rc2 = RTDirClose(pDir);
     457    if (RT_FAILURE(rc2))
     458    {
     459        RTMsgError("ls: Failed to close dir '%s', rc=%Rrc\n",
     460                   pszDir, rc2);
     461        if (RT_SUCCESS(rc))
     462            rc = rc2;
     463    }
     464
     465    if (RT_SUCCESS(rc))
     466    {
     467        PVBOXSERVICETOOLBOXDIRENTRY pNodeIt;
     468        RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXDIRENTRY, Node)
     469        {
     470            RTFMODE fMode = pNodeIt->dirEntry.Info.Attr.fMode;
     471            char cFileType;
     472            switch (fMode & RTFS_TYPE_MASK)
     473            {
     474                case RTFS_TYPE_FIFO:        cFileType = 'f'; break;
     475                case RTFS_TYPE_DEV_CHAR:    cFileType = 'c'; break;
     476                case RTFS_TYPE_DIRECTORY:   cFileType = 'd'; break;
     477                case RTFS_TYPE_DEV_BLOCK:   cFileType = 'b'; break;
     478                case RTFS_TYPE_FILE:        cFileType = '-'; break;
     479                case RTFS_TYPE_SYMLINK:     cFileType = 'l'; break;
     480                case RTFS_TYPE_SOCKET:      cFileType = 's'; break;
     481                case RTFS_TYPE_WHITEOUT:    cFileType = 'w'; break;
     482                default:
     483                    cFileType = '?';
     484                    break;
     485            }
     486            /** @todo sticy bits++ */
     487
     488            if (!fLong)
     489            {
     490                if (fParseable)
     491                {
     492                    /** @todo Skip node_id if not present/available! */
     493                    RTPrintf("ftype=%c%cnode_id=%RU64%cname_len=%RU16%cname=%s%c",
     494                             cFileType, 0, (uint64_t)pNodeIt->dirEntry.Info.Attr.u.Unix.INodeId, 0,
     495                             pNodeIt->dirEntry.cbName, 0, pNodeIt->dirEntry.szName, 0);
     496                }
     497                else
     498                    RTPrintf("%c %#18llx %3d %s\n", (uint64_t)pNodeIt->dirEntry.Info.Attr.u.Unix.INodeId,
     499                             cFileType, pNodeIt->dirEntry.cbName, pNodeIt->dirEntry.szName);
     500
     501                if (fParseable) /* End of data block. */
     502                    RTPrintf("%c%c", 0, 0);
     503            }
     504            else
     505            {
     506                if (fParseable)
     507                {
     508                    RTPrintf("ftype=%c%c", cFileType, 0);
     509                    RTPrintf("owner_mask=%c%c%c%c",
     510                             fMode & RTFS_UNIX_IRUSR ? 'r' : '-',
     511                             fMode & RTFS_UNIX_IWUSR ? 'w' : '-',
     512                             fMode & RTFS_UNIX_IXUSR ? 'x' : '-', 0);
     513                    RTPrintf("group_mask=%c%c%c%c",
     514                             fMode & RTFS_UNIX_IRGRP ? 'r' : '-',
     515                             fMode & RTFS_UNIX_IWGRP ? 'w' : '-',
     516                             fMode & RTFS_UNIX_IXGRP ? 'x' : '-', 0);
     517                    RTPrintf("other_mask=%c%c%c%c",
     518                             fMode & RTFS_UNIX_IROTH ? 'r' : '-',
     519                             fMode & RTFS_UNIX_IWOTH ? 'w' : '-',
     520                             fMode & RTFS_UNIX_IXOTH ? 'x' : '-', 0);
     521                    RTPrintf("dos_mask=%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
     522                             fMode & RTFS_DOS_READONLY          ? 'R' : '-',
     523                             fMode & RTFS_DOS_HIDDEN            ? 'H' : '-',
     524                             fMode & RTFS_DOS_SYSTEM            ? 'S' : '-',
     525                             fMode & RTFS_DOS_DIRECTORY         ? 'D' : '-',
     526                             fMode & RTFS_DOS_ARCHIVED          ? 'A' : '-',
     527                             fMode & RTFS_DOS_NT_DEVICE         ? 'd' : '-',
     528                             fMode & RTFS_DOS_NT_NORMAL         ? 'N' : '-',
     529                             fMode & RTFS_DOS_NT_TEMPORARY      ? 'T' : '-',
     530                             fMode & RTFS_DOS_NT_SPARSE_FILE    ? 'P' : '-',
     531                             fMode & RTFS_DOS_NT_REPARSE_POINT  ? 'J' : '-',
     532                             fMode & RTFS_DOS_NT_COMPRESSED     ? 'C' : '-',
     533                             fMode & RTFS_DOS_NT_OFFLINE        ? 'O' : '-',
     534                             fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-',
     535                             fMode & RTFS_DOS_NT_ENCRYPTED      ? 'E' : '-', 0);
     536
     537                    char szTimeBirth[256];
     538                    RTTimeSpecToString(&pNodeIt->dirEntry.Info.BirthTime, szTimeBirth, sizeof(szTimeBirth));
     539                    char szTimeChange[256];
     540                    RTTimeSpecToString(&pNodeIt->dirEntry.Info.ChangeTime, szTimeChange, sizeof(szTimeChange));
     541                    char szTimeModification[256];
     542                    RTTimeSpecToString(&pNodeIt->dirEntry.Info.ModificationTime, szTimeModification, sizeof(szTimeModification));
     543                    char szTimeAccess[256];
     544                    RTTimeSpecToString(&pNodeIt->dirEntry.Info.AccessTime, szTimeAccess, sizeof(szTimeAccess));
     545
     546                    RTPrintf("hlinks=%RU32%cuid=%RU32%cgid=%RU32%cst_size=%RI64%calloc=%RI64%c"
     547                             "st_birthtime=%s%cst_ctime=%s%cst_mtime=%s%cst_atime=%s%c",
     548                             pNodeIt->dirEntry.Info.Attr.u.Unix.cHardlinks, 0,
     549                             pNodeIt->dirEntry.Info.Attr.u.Unix.uid, 0,
     550                             pNodeIt->dirEntry.Info.Attr.u.Unix.gid, 0,
     551                             pNodeIt->dirEntry.Info.cbObject, 0,
     552                             pNodeIt->dirEntry.Info.cbAllocated, 0,
     553                             szTimeBirth, 0,
     554                             szTimeChange, 0,
     555                             szTimeModification, 0,
     556                             szTimeAccess, 0);
     557                    RTPrintf("cname_len=%RU16%cname=%s%c",
     558                             pNodeIt->dirEntry.cbName, 0, pNodeIt->dirEntry.szName, 0);
     559
     560                    /* End of data block. */
     561                    RTPrintf("%c%c", 0, 0);
     562                }
     563                else
     564                {
     565                    RTPrintf("%c", cFileType);
     566                    RTPrintf("%c%c%c",
     567                             fMode & RTFS_UNIX_IRUSR ? 'r' : '-',
     568                             fMode & RTFS_UNIX_IWUSR ? 'w' : '-',
     569                             fMode & RTFS_UNIX_IXUSR ? 'x' : '-');
     570                    RTPrintf("%c%c%c",
     571                             fMode & RTFS_UNIX_IRGRP ? 'r' : '-',
     572                             fMode & RTFS_UNIX_IWGRP ? 'w' : '-',
     573                             fMode & RTFS_UNIX_IXGRP ? 'x' : '-');
     574                    RTPrintf("%c%c%c",
     575                             fMode & RTFS_UNIX_IROTH ? 'r' : '-',
     576                             fMode & RTFS_UNIX_IWOTH ? 'w' : '-',
     577                             fMode & RTFS_UNIX_IXOTH ? 'x' : '-');
     578                    RTPrintf(" %c%c%c%c%c%c%c%c%c%c%c%c%c%c",
     579                             fMode & RTFS_DOS_READONLY          ? 'R' : '-',
     580                             fMode & RTFS_DOS_HIDDEN            ? 'H' : '-',
     581                             fMode & RTFS_DOS_SYSTEM            ? 'S' : '-',
     582                             fMode & RTFS_DOS_DIRECTORY         ? 'D' : '-',
     583                             fMode & RTFS_DOS_ARCHIVED          ? 'A' : '-',
     584                             fMode & RTFS_DOS_NT_DEVICE         ? 'd' : '-',
     585                             fMode & RTFS_DOS_NT_NORMAL         ? 'N' : '-',
     586                             fMode & RTFS_DOS_NT_TEMPORARY      ? 'T' : '-',
     587                             fMode & RTFS_DOS_NT_SPARSE_FILE    ? 'P' : '-',
     588                             fMode & RTFS_DOS_NT_REPARSE_POINT  ? 'J' : '-',
     589                             fMode & RTFS_DOS_NT_COMPRESSED     ? 'C' : '-',
     590                             fMode & RTFS_DOS_NT_OFFLINE        ? 'O' : '-',
     591                             fMode & RTFS_DOS_NT_NOT_CONTENT_INDEXED ? 'I' : '-',
     592                             fMode & RTFS_DOS_NT_ENCRYPTED      ? 'E' : '-');
     593                    RTPrintf(" %d %4d %4d %10lld %10lld %#llx %#llx %#llx %#llx",
     594                             pNodeIt->dirEntry.Info.Attr.u.Unix.cHardlinks,
     595                             pNodeIt->dirEntry.Info.Attr.u.Unix.uid,
     596                             pNodeIt->dirEntry.Info.Attr.u.Unix.gid,
     597                             pNodeIt->dirEntry.Info.cbObject,
     598                             pNodeIt->dirEntry.Info.cbAllocated,
     599                             pNodeIt->dirEntry.Info.BirthTime,
     600                             pNodeIt->dirEntry.Info.ChangeTime,
     601                             pNodeIt->dirEntry.Info.ModificationTime,
     602                             pNodeIt->dirEntry.Info.AccessTime);
     603                    RTPrintf(" %2d %s\n", pNodeIt->dirEntry.cbName, pNodeIt->dirEntry.szName);
     604                }
     605            }
     606            if (RT_FAILURE(rc))
     607                    break;
     608        }
     609
     610        /* If everything went fine we do the second run (if needed) ... */
     611        if (RT_SUCCESS(rc) && fRecursive)
     612        {
     613            /* Process all sub-directories. */
     614            PVBOXSERVICETOOLBOXDIRENTRY pNodeIt;
     615            RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXDIRENTRY, Node)
     616            {
     617                RTFMODE fMode = pNodeIt->dirEntry.Info.Attr.fMode;
     618                switch (fMode & RTFS_TYPE_MASK)
     619                {
     620                    //case RTFS_TYPE_SYMLINK:
     621                    case RTFS_TYPE_DIRECTORY:
     622                        {
     623                            const char *pszName = pNodeIt->dirEntry.szName;
     624                            if (   !RTStrICmp(pszName, ".")
     625                                || !RTStrICmp(pszName, ".."))
     626                            {
     627                                /* Skip dot directories. */
     628                                continue;
     629                            }
     630                            rc = VBoxServiceToolboxLsOutput(pNodeIt->dirEntry.szName, fRecursive,
     631                                                            fLong, fParseable);
     632                        }
     633                        break;
     634
     635                    default: /* Ignore the rest. */
     636                        break;
     637                }
     638                if (RT_FAILURE(rc))
     639                    break;
     640            }
     641        }
     642    }
     643
     644    /* Clean up the mess. */
     645    PVBOXSERVICETOOLBOXDIRENTRY pNode, pSafe;
     646    RTListForEachSafe(&dirList, pNode, pSafe, VBOXSERVICETOOLBOXDIRENTRY, Node)
     647    {
     648        RTListNodeRemove(&pNode->Node);
     649        RTMemFree(pNode);
     650    }
     651    return rc;
     652}
     653
     654
     655/**
     656 * Main function for tool "vbox_ls".
     657 *
     658 * @return  RTEXITCODE.
     659 * @param   argc                    Number of arguments.
     660 * @param   argv                    Pointer to argument array.
     661 */
     662static RTEXITCODE VBoxServiceToolboxLs(int argc, char **argv)
     663{
     664    static const RTGETOPTDEF s_aOptions[] =
     665    {
     666        { "--machinereadable", LS_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING },
     667        { NULL,                'l',                     RTGETOPT_REQ_NOTHING },
     668        { NULL,                'R',                     RTGETOPT_REQ_NOTHING },
     669        { "--verbose",         'v',                     RTGETOPT_REQ_NOTHING}
     670    };
     671
     672    int ch;
     673    RTGETOPTUNION ValueUnion;
     674    RTGETOPTSTATE GetState;
     675    RTGetOptInit(&GetState, argc, argv,
     676                 s_aOptions, RT_ELEMENTS(s_aOptions),
     677                 /* Index of argv to start with. */
     678#ifdef VBOXSERVICE_TOOLBOX_DEBUG
     679                 2,
     680#else
     681                 1,
     682#endif
     683                 RTGETOPTINIT_FLAGS_OPTS_FIRST);
     684
     685    int rc = VINF_SUCCESS;
     686    bool fVerbose = false;
     687    bool fLong = false;
     688    bool fMachineReadable = false;
     689    bool fRecursive = false;
     690
     691    /* Init file list. */
     692    RTLISTNODE fileList;
     693    RTListInit(&fileList);
     694
     695    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     696              && RT_SUCCESS(rc))
     697    {
     698        /* For options that require an argument, ValueUnion has received the value. */
     699        switch (ch)
     700        {
     701            case 'h':
     702                VBoxServiceToolboxShowUsage();
     703                return RTEXITCODE_SUCCESS;
     704
     705            case 'l': /* Print long format. */
     706                fLong = true;
     707                break;
     708
     709            case LS_OPT_MACHINE_READABLE:
     710                fMachineReadable = true;
     711                break;
     712
     713            case 'R': /* Recursive processing. */
     714                fRecursive = true;
     715                break;
     716
     717            case 'v':
     718                fVerbose = true;
     719                break;
     720
     721            case 'V':
     722                VBoxServiceToolboxShowVersion();
     723                return RTEXITCODE_SUCCESS;
     724
     725            case VINF_GETOPT_NOT_OPTION:
     726                {
     727                    /* Add file(s) to buffer. This enables processing multiple files
     728                     * at once.
     729                     *
     730                     * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
     731                     * processing this loop it's safe to immediately exit on syntax errors
     732                     * or showing the help text (see above). */
     733                    rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, ValueUnion.psz);
     734                    break;
     735                }
     736
     737            default:
     738                return RTGetOptPrintError(ch, &ValueUnion);
     739        }
     740    }
     741
     742    if (RT_SUCCESS(rc))
     743    {
     744        /* If not files given add current directory to list. */
     745        if (RTListIsEmpty(&fileList))
     746        {
     747            char szDirCur[RTPATH_MAX + 1];
     748            rc = RTPathGetCurrent(szDirCur, sizeof(szDirCur));
     749            if (RT_SUCCESS(rc))
     750            {
     751                rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, szDirCur);
     752                if (RT_FAILURE(rc))
     753                    RTMsgError("ls: Adding current directory failed, rc=%Rrc\n", rc);
     754            }
     755            else
     756                RTMsgError("ls: Getting current directory failed, rc=%Rrc\n", rc);
     757        }
     758
     759        /* Print magic/version. */
     760        if (fMachineReadable)
     761            RTPrintf("hdr_id=vbt_ls%chdr_ver=%u%c", 0, 1 /* Version 1 */, 0);
     762
     763        PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
     764        RTListForEach(&fileList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
     765        {
     766            rc = VBoxServiceToolboxLsOutput(pNodeIt->pszName,
     767                                            fRecursive, fLong, fMachineReadable);
     768            if (RT_FAILURE(rc))
     769                RTMsgError("ls: Failed while enumerating directory '%s', rc=%Rrc\n",
     770                           pNodeIt->pszName, rc);
     771        }
     772
     773        if (fMachineReadable) /* Output termination. */
     774            RTPrintf("%c%c%c%c", 0, 0, 0, 0);
     775    }
     776    else if (fVerbose)
     777        RTMsgError("ls: Failed with rc=%Rrc\n", rc);
     778
     779    VBoxServiceToolboxPathBufDestroy(&fileList);
     780    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     781}
     782
     783
     784/**
    218785 * Main function for tool "vbox_mkdir".
    219786 *
     
    224791static RTEXITCODE VBoxServiceToolboxMkDir(int argc, char **argv)
    225792{
    226      static const RTGETOPTDEF s_aOptions[] =
    227      {
    228          { "--mode",     'm', RTGETOPT_REQ_STRING },
    229          { "--parents",  'p', RTGETOPT_REQ_NOTHING },
    230          { "--verbose",  'v', RTGETOPT_REQ_NOTHING }
    231      };
    232 
    233      int ch;
    234      RTGETOPTUNION ValueUnion;
    235      RTGETOPTSTATE GetState;
    236      RTGetOptInit(&GetState, argc, argv,
    237                   s_aOptions, RT_ELEMENTS(s_aOptions),
    238                   /* Index of argv to start with. */
     793    static const RTGETOPTDEF s_aOptions[] =
     794    {
     795        { "--mode",     'm', RTGETOPT_REQ_STRING },
     796        { "--parents",  'p', RTGETOPT_REQ_NOTHING},
     797        { "--verbose",  'v', RTGETOPT_REQ_NOTHING}
     798    };
     799
     800    int ch;
     801    RTGETOPTUNION ValueUnion;
     802    RTGETOPTSTATE GetState;
     803    RTGetOptInit(&GetState, argc, argv,
     804                 s_aOptions, RT_ELEMENTS(s_aOptions),
     805                 /* Index of argv to start with. */
    239806#ifdef VBOXSERVICE_TOOLBOX_DEBUG
    240                   2,
     807                 2,
    241808#else
    242                   1,
     809                 1,
    243810#endif
    244                   RTGETOPTINIT_FLAGS_OPTS_FIRST);
    245 
    246      int rc = VINF_SUCCESS;
    247      bool fMakeParentDirs = false;
    248      bool fVerbose = false;
    249 
    250      RTFMODE newMode = 0;
    251      RTFMODE dirMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO;
    252 
    253      /* Init directory list. */
    254      RTLISTNODE dirList;
    255      RTListInit(&dirList);
    256 
    257      while (   (ch = RTGetOpt(&GetState, &ValueUnion))
    258             && RT_SUCCESS(rc))
    259      {
    260          /* For options that require an argument, ValueUnion has received the value. */
    261          switch (ch)
    262          {
    263              case 'h':
    264                  VBoxServiceToolboxShowUsage();
    265                  return RTEXITCODE_SUCCESS;
    266 
    267              case 'p':
    268                  fMakeParentDirs = true;
    269                  break;
    270 
    271              case 'm':
    272                  rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 8 /* Base */, &newMode);
    273                  if (RT_FAILURE(rc)) /* Only octet based values supported right now! */
    274                  {
    275                      RTMsgError("mkdir: Mode flag strings not implemented yet! Use octal numbers instead.\n");
    276                      return RTEXITCODE_SYNTAX;
    277                  }
    278                  break;
    279 
    280              case 'v':
    281                  fVerbose = true;
    282                  break;
    283 
    284              case 'V':
    285                  VBoxServiceToolboxShowVersion();
    286                  return RTEXITCODE_SUCCESS;
    287 
    288              case VINF_GETOPT_NOT_OPTION:
    289              {
    290                  /* Add path(s) to buffer. This enables processing multiple paths
    291                   * at once.
    292                   *
    293                   * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
    294                   * processing this loop it's safe to immediately exit on syntax errors
    295                   * or showing the help text (see above). */
    296                  rc = VBoxServiceToolboxPathBufAddPathEntry(&dirList, ValueUnion.psz);
    297                  break;
    298              }
    299 
    300              default:
    301                  return RTGetOptPrintError(ch, &ValueUnion);
    302          }
    303      }
    304 
    305      if (RT_SUCCESS(rc))
    306      {
    307          if (fMakeParentDirs || newMode)
    308          {
     811                 RTGETOPTINIT_FLAGS_OPTS_FIRST);
     812
     813    int rc = VINF_SUCCESS;
     814    bool fMakeParentDirs = false;
     815    bool fVerbose = false;
     816
     817    RTFMODE newMode = 0;
     818    RTFMODE dirMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO;
     819
     820    /* Init directory list. */
     821    RTLISTNODE dirList;
     822    RTListInit(&dirList);
     823
     824    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     825              && RT_SUCCESS(rc))
     826    {
     827        /* For options that require an argument, ValueUnion has received the value. */
     828        switch (ch)
     829        {
     830            case 'h':
     831                VBoxServiceToolboxShowUsage();
     832                return RTEXITCODE_SUCCESS;
     833
     834            case 'p':
     835                fMakeParentDirs = true;
     836                break;
     837
     838            case 'm':
     839                rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 8 /* Base */, &newMode);
     840                if (RT_FAILURE(rc)) /* Only octet based values supported right now! */
     841                {
     842                    RTMsgError("mkdir: Mode flag strings not implemented yet! Use octal numbers instead.\n");
     843                    return RTEXITCODE_SYNTAX;
     844                }
     845                break;
     846
     847            case 'v':
     848                fVerbose = true;
     849                break;
     850
     851            case 'V':
     852                VBoxServiceToolboxShowVersion();
     853                return RTEXITCODE_SUCCESS;
     854
     855            case VINF_GETOPT_NOT_OPTION:
     856                {
     857                    /* Add path(s) to buffer. This enables processing multiple paths
     858                     * at once.
     859                     *
     860                     * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
     861                     * processing this loop it's safe to immediately exit on syntax errors
     862                     * or showing the help text (see above). */
     863                    rc = VBoxServiceToolboxPathBufAddPathEntry(&dirList, ValueUnion.psz);
     864                    break;
     865                }
     866
     867            default:
     868                return RTGetOptPrintError(ch, &ValueUnion);
     869        }
     870    }
     871
     872    if (RT_SUCCESS(rc))
     873    {
     874        if (fMakeParentDirs || newMode)
     875        {
    309876#ifndef RT_OS_WINDOWS
    310              mode_t umaskMode = umask(0); /* Get current umask. */
    311              if (newMode)
     877            mode_t umaskMode = umask(0); /* Get current umask. */
     878            if (newMode)
    312879                dirMode = newMode;
    313880#endif
    314          }
    315 
    316          PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
    317          RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
    318          {
    319              rc = fMakeParentDirs ?
    320                     RTDirCreateFullPath(pNodeIt->pszName, dirMode)
    321                   : RTDirCreate(pNodeIt->pszName, dirMode);
    322 
    323              if (RT_SUCCESS(rc) && fVerbose)
    324                  RTMsgError("mkdir: Created directory 's', mode %#RTfmode\n", pNodeIt->pszName, dirMode);
    325              else if (RT_FAILURE(rc)) /** @todo Add a switch with more helpful error texts! */
    326              {
    327                  PCRTSTATUSMSG pMsg = RTErrGet(rc);
    328                  if (pMsg)
    329                      RTMsgError("mkdir: Could not create directory '%s': %s\n",
    330                                 pNodeIt->pszName, pMsg->pszMsgFull);
    331                  else
    332                      RTMsgError("mkdir: Could not create directory '%s', rc=%Rrc\n", pNodeIt->pszName, rc);
    333                  break;
    334              }
    335          }
    336      }
    337      else if (fVerbose)
    338          RTMsgError("mkdir: Failed with rc=%Rrc\n", rc);
    339 
    340      VBoxServiceToolboxPathBufDestroy(&dirList);
    341      return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    342 }
    343 
    344 
    345 /**
    346  * Main function for tool "vbox_cat".
    347  *
    348  * @return  RTEXITCODE.
    349  * @param   argc                    Number of arguments.
    350  * @param   argv                    Pointer to argument array.
    351  */
    352 static RTEXITCODE VBoxServiceToolboxCat(int argc, char **argv)
    353 {
    354      static const RTGETOPTDEF s_aOptions[] =
    355      {
    356          /* Sorted by short ops. */
    357          { "--show-all",            'a',                         RTGETOPT_REQ_NOTHING },
    358          { "--number-nonblank",     'b',                         RTGETOPT_REQ_NOTHING },
    359          { NULL,                    'e',                         RTGETOPT_REQ_NOTHING },
    360          { NULL,                    'E',                         RTGETOPT_REQ_NOTHING },
    361          { "--flags",               'f',                         RTGETOPT_REQ_STRING  },
    362          { "--no-content-indexed",  CAT_OPT_NO_CONTENT_INDEXED,  RTGETOPT_REQ_NOTHING },
    363          { "--number",              'n',                         RTGETOPT_REQ_NOTHING },
    364          { "--output",              'o',                         RTGETOPT_REQ_STRING  },
    365          { "--squeeze-blank",       's',                         RTGETOPT_REQ_NOTHING },
    366          { NULL,                    't',                         RTGETOPT_REQ_NOTHING },
    367          { "--show-tabs",           'T',                         RTGETOPT_REQ_NOTHING },
    368          { NULL,                    'u',                         RTGETOPT_REQ_NOTHING },
    369          { "--show-noneprinting",   'v',                         RTGETOPT_REQ_NOTHING }
    370      };
    371 
    372      int ch;
    373      RTGETOPTUNION ValueUnion;
    374      RTGETOPTSTATE GetState;
    375 
    376      RTGetOptInit(&GetState, argc, argv,
    377                   s_aOptions, RT_ELEMENTS(s_aOptions),
    378                   /* Index of argv to start with. */
    379 #ifdef VBOXSERVICE_TOOLBOX_DEBUG
    380                   2,
    381 #else
    382                   1,
    383 #endif
    384                   0);
    385 
    386      int rc = VINF_SUCCESS;
    387      bool fUsageOK = true;
    388 
    389      char szOutput[RTPATH_MAX] = { 0 };
    390      RTFILE hOutput = NIL_RTFILE;
    391      uint32_t fFlags = RTFILE_O_CREATE_REPLACE /* Output file flags. */
    392                      | RTFILE_O_WRITE
    393                      | RTFILE_O_DENY_WRITE;
    394 
    395      /* Init directory list. */
    396      RTLISTNODE inputList;
    397      RTListInit(&inputList);
    398 
    399      while (   (ch = RTGetOpt(&GetState, &ValueUnion))
    400             && RT_SUCCESS(rc))
    401      {
    402          /* For options that require an argument, ValueUnion has received the value. */
    403          switch (ch)
    404          {
    405              case 'a':
    406              case 'b':
    407              case 'e':
    408              case 'E':
    409              case 'n':
    410              case 's':
    411              case 't':
    412              case 'T':
    413              case 'v':
    414                  RTMsgError("cat: Sorry, option '%s' is not implemented yet!\n",
    415                             ValueUnion.pDef->pszLong);
    416                  rc = VERR_INVALID_PARAMETER;
    417                  break;
    418 
    419              case 'h':
    420                  VBoxServiceToolboxShowUsage();
    421                  return RTEXITCODE_SUCCESS;
    422 
    423              case 'o':
    424                  if (!RTStrPrintf(szOutput, sizeof(szOutput), ValueUnion.psz))
    425                      rc = VERR_NO_MEMORY;
    426                  break;
    427 
    428              case 'u':
    429                  /* Ignored. */
    430                  break;
    431 
    432              case 'V':
    433                  VBoxServiceToolboxShowVersion();
    434                  return RTEXITCODE_SUCCESS;
    435 
    436              case CAT_OPT_NO_CONTENT_INDEXED:
    437                  fFlags |= RTFILE_O_NOT_CONTENT_INDEXED;
    438                  break;
    439 
    440              case VINF_GETOPT_NOT_OPTION:
    441              {
    442                  /* Add file(s) to buffer. This enables processing multiple paths
    443                   * at once.
    444                   *
    445                   * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
    446                   * processing this loop it's safe to immediately exit on syntax errors
    447                   * or showing the help text (see above). */
    448                  rc = VBoxServiceToolboxPathBufAddPathEntry(&inputList, ValueUnion.psz);
    449                  break;
    450              }
    451 
    452              default:
    453                  return RTGetOptPrintError(ch, &ValueUnion);
    454          }
    455      }
    456 
    457      if (RT_SUCCESS(rc))
    458      {
    459          if (strlen(szOutput))
    460          {
    461              rc = RTFileOpen(&hOutput, szOutput, fFlags);
    462              if (RT_FAILURE(rc))
    463                  RTMsgError("cat: Could not create output file '%s'! rc=%Rrc\n",
    464                             szOutput, rc);
    465          }
    466 
    467          if (RT_SUCCESS(rc))
    468          {
    469              /* Process each input file. */
    470              PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
    471              RTFILE hInput = NIL_RTFILE;
    472              RTListForEach(&inputList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
    473              {
    474                  rc = RTFileOpen(&hInput, pNodeIt->pszName,
    475                                  RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    476                  if (RT_SUCCESS(rc))
    477                  {
    478                      rc = VBoxServiceToolboxCatOutput(hInput, hOutput);
    479                      RTFileClose(hInput);
    480                  }
    481                  else
    482                  {
    483                      PCRTSTATUSMSG pMsg = RTErrGet(rc);
    484                      if (pMsg)
    485                          RTMsgError("cat: Could not open input file '%s': %s\n",
    486                                     pNodeIt->pszName, pMsg->pszMsgFull);
    487                      else
    488                          RTMsgError("cat: Could not open input file '%s', rc=%Rrc\n", pNodeIt->pszName, rc);
    489                  }
    490 
    491                  if (RT_FAILURE(rc))
    492                      break;
    493              }
    494 
    495              /* If not input files were defined, process stdin. */
    496              if (RTListNodeIsFirst(&inputList, &inputList))
    497                  rc = VBoxServiceToolboxCatOutput(hInput, hOutput);
    498          }
    499      }
    500 
    501      if (hOutput != NIL_RTFILE)
    502          RTFileClose(hOutput);
    503      VBoxServiceToolboxPathBufDestroy(&inputList);
    504 
    505      return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     881        }
     882
     883        PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
     884        RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
     885        {
     886            rc = fMakeParentDirs ?
     887                 RTDirCreateFullPath(pNodeIt->pszName, dirMode)
     888                 : RTDirCreate(pNodeIt->pszName, dirMode);
     889
     890            if (RT_SUCCESS(rc) && fVerbose)
     891                RTMsgError("mkdir: Created directory 's', mode %#RTfmode\n", pNodeIt->pszName, dirMode);
     892            else if (RT_FAILURE(rc)) /** @todo Add a switch with more helpful error texts! */
     893            {
     894                PCRTSTATUSMSG pMsg = RTErrGet(rc);
     895                if (pMsg)
     896                    RTMsgError("mkdir: Could not create directory '%s': %s\n",
     897                               pNodeIt->pszName, pMsg->pszMsgFull);
     898                else
     899                    RTMsgError("mkdir: Could not create directory '%s', rc=%Rrc\n", pNodeIt->pszName, rc);
     900                break;
     901            }
     902        }
     903    }
     904    else if (fVerbose)
     905        RTMsgError("mkdir: Failed with rc=%Rrc\n", rc);
     906
     907    VBoxServiceToolboxPathBufDestroy(&dirList);
     908    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    506909}
    507910
     
    516919static RTEXITCODE VBoxServiceToolboxStat(int argc, char **argv)
    517920{
    518      static const RTGETOPTDEF s_aOptions[] =
    519      {
    520          { "--file-system",     'f', RTGETOPT_REQ_NOTHING },
    521          { "--dereference",     'L', RTGETOPT_REQ_NOTHING },
    522          { "--terse",           't', RTGETOPT_REQ_NOTHING },
    523          { "--verbose",         'v', RTGETOPT_REQ_NOTHING }
    524      };
    525 
    526      int ch;
    527      RTGETOPTUNION ValueUnion;
    528      RTGETOPTSTATE GetState;
    529      RTGetOptInit(&GetState, argc, argv,
    530                   s_aOptions, RT_ELEMENTS(s_aOptions),
    531                    /* Index of argv to start with. */
     921    static const RTGETOPTDEF s_aOptions[] =
     922    {
     923        { "--file-system",     'f', RTGETOPT_REQ_NOTHING },
     924        { "--dereference",     'L', RTGETOPT_REQ_NOTHING},
     925        { "--terse",           't', RTGETOPT_REQ_NOTHING},
     926        { "--verbose",         'v', RTGETOPT_REQ_NOTHING}
     927    };
     928
     929    int ch;
     930    RTGETOPTUNION ValueUnion;
     931    RTGETOPTSTATE GetState;
     932    RTGetOptInit(&GetState, argc, argv,
     933                 s_aOptions, RT_ELEMENTS(s_aOptions),
     934                 /* Index of argv to start with. */
    532935#ifdef VBOXSERVICE_TOOLBOX_DEBUG
    533                   2,
     936                 2,
    534937#else
    535                   1,
     938                 1,
    536939#endif
    537                   RTGETOPTINIT_FLAGS_OPTS_FIRST);
    538 
    539      int rc = VINF_SUCCESS;
    540      bool fVerbose = false;
    541 
    542      /* Init file list. */
    543      RTLISTNODE fileList;
    544      RTListInit(&fileList);
    545 
    546      while (   (ch = RTGetOpt(&GetState, &ValueUnion))
    547             && RT_SUCCESS(rc))
    548      {
    549          /* For options that require an argument, ValueUnion has received the value. */
    550          switch (ch)
    551          {
    552              case 'h':
    553                  VBoxServiceToolboxShowUsage();
    554                  return RTEXITCODE_SUCCESS;
    555 
    556              case 'f':
    557              case 'L':
    558                  RTMsgError("stat: Sorry, option '%s' is not implemented yet!\n",
    559                             ValueUnion.pDef->pszLong);
    560                  rc = VERR_INVALID_PARAMETER;
    561                  break;
    562 
    563              case 'v':
    564                  fVerbose = true;
    565                  break;
    566 
    567              case 'V':
    568                  VBoxServiceToolboxShowVersion();
    569                  return RTEXITCODE_SUCCESS;
    570 
    571              case VINF_GETOPT_NOT_OPTION:
    572              {
    573                  /* Add file(s) to buffer. This enables processing multiple files
    574                   * at once.
    575                   *
    576                   * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
    577                   * processing this loop it's safe to immediately exit on syntax errors
    578                   * or showing the help text (see above). */
    579                  rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, ValueUnion.psz);
    580                  break;
    581              }
    582 
    583              default:
    584                  return RTGetOptPrintError(ch, &ValueUnion);
    585          }
    586      }
    587 
    588      if (RT_SUCCESS(rc))
    589      {
    590          PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
    591          RTListForEach(&fileList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
    592          {
    593              /* Only check for file existence for now. */
    594              if (RTFileExists(pNodeIt->pszName))
    595              {
    596                  /** @todo Do some more work (query size etc.) here later.
    597                   *        Not needed for now. */
    598              }
    599              else
    600              {
    601                  RTMsgError("stat: Cannot stat for '%s': No such file or directory\n",
    602                             pNodeIt->pszName);
    603                  rc = VERR_FILE_NOT_FOUND;
    604                  /* Do not break here -- process every file in the list
    605                   * and keep failing rc. */
    606              }
    607          }
    608 
    609          if (RTListIsEmpty(&fileList))
    610              RTMsgError("stat: Missing operand\n");
    611      }
    612      else if (fVerbose)
    613          RTMsgError("stat: Failed with rc=%Rrc\n", rc);
    614 
    615      VBoxServiceToolboxPathBufDestroy(&fileList);
    616      return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     940                 RTGETOPTINIT_FLAGS_OPTS_FIRST);
     941
     942    int rc = VINF_SUCCESS;
     943    bool fVerbose = false;
     944
     945    /* Init file list. */
     946    RTLISTNODE fileList;
     947    RTListInit(&fileList);
     948
     949    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     950              && RT_SUCCESS(rc))
     951    {
     952        /* For options that require an argument, ValueUnion has received the value. */
     953        switch (ch)
     954        {
     955            case 'h':
     956                VBoxServiceToolboxShowUsage();
     957                return RTEXITCODE_SUCCESS;
     958
     959            case 'f':
     960            case 'L':
     961                RTMsgError("stat: Sorry, option '%s' is not implemented yet!\n",
     962                           ValueUnion.pDef->pszLong);
     963                rc = VERR_INVALID_PARAMETER;
     964                break;
     965
     966            case 'v':
     967                fVerbose = true;
     968                break;
     969
     970            case 'V':
     971                VBoxServiceToolboxShowVersion();
     972                return RTEXITCODE_SUCCESS;
     973
     974            case VINF_GETOPT_NOT_OPTION:
     975                {
     976                    /* Add file(s) to buffer. This enables processing multiple files
     977                     * at once.
     978                     *
     979                     * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
     980                     * processing this loop it's safe to immediately exit on syntax errors
     981                     * or showing the help text (see above). */
     982                    rc = VBoxServiceToolboxPathBufAddPathEntry(&fileList, ValueUnion.psz);
     983                    break;
     984                }
     985
     986            default:
     987                return RTGetOptPrintError(ch, &ValueUnion);
     988        }
     989    }
     990
     991    if (RT_SUCCESS(rc))
     992    {
     993        PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
     994        RTListForEach(&fileList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
     995        {
     996            /* Only check for file existence for now. */
     997            if (RTFileExists(pNodeIt->pszName))
     998            {
     999                /** @todo Do some more work (query size etc.) here later.
     1000                 *        Not needed for now. */
     1001            }
     1002            else
     1003            {
     1004                RTMsgError("stat: Cannot stat for '%s': No such file or directory\n",
     1005                           pNodeIt->pszName);
     1006                rc = VERR_FILE_NOT_FOUND;
     1007                /* Do not break here -- process every file in the list
     1008                 * and keep failing rc. */
     1009            }
     1010        }
     1011
     1012        if (RTListIsEmpty(&fileList))
     1013            RTMsgError("stat: Missing operand\n");
     1014    }
     1015    else if (fVerbose)
     1016        RTMsgError("stat: Failed with rc=%Rrc\n", rc);
     1017
     1018    VBoxServiceToolboxPathBufDestroy(&fileList);
     1019    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    6171020}
    6181021
     
    6421045        }
    6431046
     1047        if (   !strcmp(argv[iCmdIdx], "ls")
     1048            || !strcmp(argv[iCmdIdx], "vbox_ls"))
     1049        {
     1050            *prcExit = VBoxServiceToolboxLs(argc, argv);
     1051            return true;
     1052        }
     1053
    6441054        if (   !strcmp(argv[iCmdIdx], "mkdir")
    6451055            || !strcmp(argv[iCmdIdx], "vbox_mkdir"))
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