RTDECL(int) RTManifestWriteStandardToFile(RTMANIFEST hManifest, const char *pszFilename)
{
    RTFILE      hFile;
    uint32_t    fFlags = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE;
    int rc = RTFileOpen(&hFile, pszFilename, fFlags);
    if (RT_SUCCESS(rc))
    {
        RTVFSIOSTREAM hVfsIos;
        rc = RTVfsIoStrmFromRTFile(hFile, fFlags, true /*fLeaveOpen*/, &hVfsIos);
        if (RT_SUCCESS(rc))
        {
            rc = RTManifestWriteStandard(hManifest, hVfsIos);
            RTVfsIoStrmRelease(hVfsIos);
        }
        RTFileClose(hFile);
    }
    return rc;
}
Beispiel #2
0
/**
 * Verifies the manifest and its signature.
 *
 * @returns VBox status code, failures with message.
 * @param   hOurManifest    The manifest we compiled.
 * @param   hManifestFile   The manifest file in the extension pack.
 * @param   hSignatureFile  The manifest signature file.
 * @param   pszError            Where to store an error message on failure.
 * @param   cbError             The size of the buffer @a pszError points to.
 */
static int vboxExtPackVerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile,
                                                 char *pszError, size_t cbError)
{
    /*
     * Read the manifest from the extension pack.
     */
    int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL);
    if (RT_FAILURE(rc))
        return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsFileSeek failed: %Rrc", rc);

    RTMANIFEST hTheirManifest;
    rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest);
    if (RT_FAILURE(rc))
        return vboxExtPackReturnError(rc, pszError, cbError, "RTManifestCreate failed: %Rrc", rc);

    RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile);
    rc = RTManifestReadStandard(hTheirManifest, hVfsIos);
    RTVfsIoStrmRelease(hVfsIos);
    if (RT_SUCCESS(rc))
    {
        /*
         * Compare the manifests.
         */
        static const char *s_apszIgnoreEntries[] =
        {
            VBOX_EXTPACK_MANIFEST_NAME,
            VBOX_EXTPACK_SIGNATURE_NAME,
            "./" VBOX_EXTPACK_MANIFEST_NAME,
            "./" VBOX_EXTPACK_SIGNATURE_NAME,
            NULL
        };
        char szError[RTPATH_MAX];
        rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL,
                                RTMANIFEST_EQUALS_IGN_MISSING_ATTRS /*fFlags*/,
                                szError, sizeof(szError));
        if (RT_SUCCESS(rc))
        {
            /*
             * Validate the manifest file signature.
             */
            /** @todo implement signature stuff */
            NOREF(hSignatureFile);

        }
        else if (rc == VERR_NOT_EQUAL && szError[0])
            vboxExtPackSetError(pszError, cbError, "Manifest mismatch: %s", szError);
        else
            vboxExtPackSetError(pszError, cbError, "RTManifestEqualsEx failed: %Rrc", rc);
#if 0
        RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM;
        RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut);
        RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL);
        RTManifestWriteStandard(hOurManifest, hVfsIosStdOut);
        RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL);
        RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut);
#endif
    }
    else
        vboxExtPackSetError(pszError, cbError, "Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc);

    RTManifestRelease(hTheirManifest);
    return rc;
}
/**
 * Verify a manifest.
 *
 * @returns Program exit code, failures with error message.
 * @param   pszManifest         The manifest file. NULL if standard input.
 * @param   fStdFormat          Whether to expect standard format (true) or
 *                              java format (false).
 * @param   pszChDir            The directory to change into before processing
 *                              the files in the manifest.
 */
static RTEXITCODE rtManifestDoVerify(const char *pszManifest, bool fStdFormat, const char *pszChDir)
{
    /*
     * Open the manifest.
     */
    int             rc;
    RTVFSIOSTREAM   hVfsIos;
    if (!pszManifest)
    {
        rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT, RTFILE_O_READ, false /*fLeaveOpen*/, &hVfsIos);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to prepare standard input for reading: %Rrc", rc);
    }
    else
    {
        const char *pszError;
        rc = RTVfsChainOpenIoStream(pszManifest, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, &hVfsIos, &pszError);
        if (RT_FAILURE(rc))
        {
            if (pszError && *pszError)
                return RTMsgErrorExit(RTEXITCODE_FAILURE,
                                      "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
                                      "    '%s'\n",
                                      "     %*s^\n",
                                      rc, pszManifest, pszError - pszManifest, "");
            return RTMsgErrorExit(RTEXITCODE_FAILURE,
                                  "Failed with %Rrc opening the input manifest '%s'", rc, pszManifest);
        }
    }

    /*
     * Read it.
     */
    RTMANIFEST hManifest;
    rc = RTManifestCreate(0 /*fFlags*/, &hManifest);
    if (RT_SUCCESS(rc))
    {
        if (fStdFormat)
        {
            char szErr[4096 + 1024];
            rc = RTManifestReadStandardEx(hManifest, hVfsIos, szErr, sizeof(szErr));
            if (RT_SUCCESS(rc))
            {
                RTVfsIoStrmRelease(hVfsIos);
                hVfsIos = NIL_RTVFSIOSTREAM;

                /*
                 * Do the verification.
                 */
                /** @todo We're missing some enumeration APIs here! */
                RTMsgError("The manifest read fine, but the actual verification code is yet to be written. Sorry.");
                rc = VERR_NOT_IMPLEMENTED;
#if 1 /* For now, just write the manifest to stdout so we can test the read routine. */
                RTVFSIOSTREAM hVfsIosOut;
                rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, false /*fLeaveOpen*/, &hVfsIosOut);
                if (RT_SUCCESS(rc))
                {
                    RTManifestWriteStandard(hManifest, hVfsIosOut);
                    RTVfsIoStrmRelease(hVfsIosOut);
                }
#endif
            }
            else if (szErr[0])
                RTMsgError("Error reading manifest: %s", szErr);
            else
                RTMsgError("Error reading manifest: %Rrc", rc);
        }
        else
        {
            RTMsgError("Support for Java manifest files is not implemented yet");
            rc = VERR_NOT_IMPLEMENTED;
        }
        RTManifestRelease(hManifest);
    }

    RTVfsIoStrmRelease(hVfsIos);
    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
/**
 * Create a manifest from the specified input files.
 *
 * @returns Program exit code, failures with error message.
 * @param   pszManifest         The name of the output manifest file.  NULL if
 *                              it should be written to standard output.
 * @param   fStdFormat          Whether to expect standard format (true) or
 *                              java format (false).
 * @param   pszChDir            The directory to change into before processing
 *                              the file arguments.
 * @param   fAttr               The file attributes to put in the manifest.
 * @param   pGetState           The RTGetOpt state.
 * @param   pUnion              What the last RTGetOpt() call returned.
 * @param   chOpt               What the last RTGetOpt() call returned.
 */
static RTEXITCODE rtManifestDoCreate(const char *pszManifest, bool fStdFormat, const char *pszChDir, uint32_t fAttr,
                                     PRTGETOPTSTATE pGetState, PRTGETOPTUNION pUnion, int chOpt)
{
    /*
     * Open the manifest file.
     */
    int rc;
    RTVFSIOSTREAM hVfsIos;
    if (!pszManifest)
    {
        rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, false /*fLeaveOpen*/, &hVfsIos);
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to prepare standard output for writing: %Rrc", rc);
    }
    else
    {
        const char *pszError;
        rc = RTVfsChainOpenIoStream(pszManifest, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
                                    &hVfsIos, &pszError);
        if (RT_FAILURE(rc))
        {
            if (pszError && *pszError)
                return RTMsgErrorExit(RTEXITCODE_FAILURE,
                                      "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
                                      "    '%s'\n",
                                      "     %*s^\n",
                                      rc, pszManifest, pszError - pszManifest, "");
            return RTMsgErrorExit(RTEXITCODE_FAILURE,
                                  "Failed with %Rrc opening the manifest '%s'", rc, pszManifest);
        }
    }

    /*
     * Create the internal manifest.
     */
    RTMANIFEST hManifest;
    rc = RTManifestCreate(0 /*fFlags*/, &hManifest);
    if (RT_SUCCESS(rc))
    {
        /*
         * Change directory and start processing the specified files.
         */
        if (pszChDir)
        {
            rc = RTPathSetCurrent(pszChDir);
            if (RT_FAILURE(rc))
                RTMsgError("Failed to change directory to '%s': %Rrc", pszChDir, rc);
        }
        if (RT_SUCCESS(rc))
        {
            while (chOpt == VINF_GETOPT_NOT_OPTION)
            {
                rc = rtManifestAddFileToManifest(hManifest, pUnion->psz, fAttr);
                if (RT_FAILURE(rc))
                    break;

                /* next */
                chOpt = RTGetOpt(pGetState, pUnion);
            }
            if (RT_SUCCESS(rc) && chOpt != 0)
            {
                RTGetOptPrintError(chOpt, pUnion);
                rc = chOpt < 0 ? chOpt : -chOpt;
            }
        }

        /*
         * Write the manifest.
         */
        if (RT_SUCCESS(rc))
        {
            if (fStdFormat)
            {
                rc = RTManifestWriteStandard(hManifest, hVfsIos);
                if (RT_FAILURE(rc))
                    RTMsgError("RTManifestWriteStandard failed: %Rrc", rc);
            }
            else
            {
                RTMsgError("Support for Java manifest files is not implemented yet");
                rc = VERR_NOT_IMPLEMENTED;
            }
        }

        RTManifestRelease(hManifest);
    }

    RTVfsIoStrmRelease(hVfsIos);
    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}