/** * Opens the output file. * * @returns Command exit, error messages written using RTMsg*. * * @param pszFile The input filename. * @param pOpts The options, szOutput will be filled in by this * function on success. * @param phVfsIos Where to return the output stream handle. * * @remarks This is actually not quite the way we need to do things. * * First of all, we need a GZIP file system stream for a real GZIP * implementation, since there may be more than one file in the gzipped * file. * * Second, we need to open the output files as we encounter files in the input * file system stream. The gzip format contains timestamp and usually a * filename, the default is to use this name (see the --no-name * option). */ static RTEXITCODE gzipOpenOutput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos) { int rc; if (!strcmp(pszFile, "-") || pOpts->fStdOut) { strcpy(pOpts->szOutput, "-"); if ( !pOpts->fForce && !pOpts->fDecompress && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT)) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Yeah, right. I'm not writing any compressed data to the terminal without --force.\n"); rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, true /*fLeaveOpen*/, phVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard output: %Rrc", rc); } else { Assert(!RTVfsChainIsSpec(pszFile)); /* Construct an output filename. */ rc = RTStrCopy(pOpts->szOutput, sizeof(pOpts->szOutput), pszFile); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc); if (pOpts->fDecompress) { /** @todo take filename from archive? */ size_t cchSuff = strlen(pOpts->pszSuff); Assert(cchSuff > 0); size_t cch = strlen(pOpts->szOutput); if ( cch <= cchSuff || strcmp(&pOpts->szOutput[cch - cchSuff], pOpts->pszSuff)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Input file does not end with: '%s'", pOpts->pszSuff); pOpts->szOutput[cch - cchSuff] = '\0'; if (!RTPathFilename(pOpts->szOutput)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: Input file name is all suffix."); } else { rc = RTStrCat(pOpts->szOutput, sizeof(pOpts->szOutput), pOpts->pszSuff); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc); } /* Open the output file. */ uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE; if (pOpts->fForce) fOpen |= RTFILE_O_CREATE_REPLACE; else fOpen |= RTFILE_O_CREATE; rc = RTVfsIoStrmOpenNormal(pOpts->szOutput, fOpen, phVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening output file '%s': %Rrc", pOpts->szOutput, rc); } return RTEXITCODE_SUCCESS; }
static void tstVfsIoFromStandardHandle(RTTEST hTest, RTHANDLESTD enmHandle) { RTTestSubF(hTest, "RTVfsIoStrmFromStdHandle(%s)", StandardHandleToString(enmHandle)); RTVFSIOSTREAM hVfsIos = NIL_RTVFSIOSTREAM; int rc = RTVfsIoStrmFromStdHandle(enmHandle, 0, true /*fLeaveOpen*/, &hVfsIos); if (RT_SUCCESS(rc)) { if ( enmHandle == RTHANDLESTD_OUTPUT || enmHandle == RTHANDLESTD_ERROR) { char szTmp[80]; size_t cchTmp = RTStrPrintf(szTmp, sizeof(szTmp), "Test output to %s\n", StandardHandleToString(enmHandle)); size_t cbWritten; RTTESTI_CHECK_RC(rc = RTVfsIoStrmWrite(hVfsIos, szTmp, cchTmp, true /*fBlocking*/, &cbWritten), VINF_SUCCESS); if (RT_SUCCESS(rc)) RTTESTI_CHECK(cbWritten == cchTmp); } uint32_t cRefs = RTVfsIoStrmRelease(hVfsIos); RTTESTI_CHECK_MSG(cRefs == 0, ("cRefs=%#x\n", cRefs)); } else RTTestFailed(hTest, "Error creating VFS I/O stream for %s: %Rrc\n", StandardHandleToString(enmHandle), rc); }
/** * Opens the input file. * * @returns Command exit, error messages written using RTMsg*. * * @param pszFile The input filename. * @param pOpts The options, szOutput will be filled in by this * function on success. * @param phVfsIos Where to return the input stream handle. */ static RTEXITCODE gzipOpenInput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos) { int rc; pOpts->pszInput = pszFile; if (!strcmp(pszFile, "-")) { if ( !pOpts->fForce && pOpts->fDecompress && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT)) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Yeah, right. I'm not reading any compressed data from the terminal without --force.\n"); rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, true /*fLeaveOpen*/, phVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard input: %Rrc", rc); } else { uint32_t offError = 0; RTERRINFOSTATIC ErrInfo; rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, phVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo)); if (RT_FAILURE(rc)) return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core); } return RTEXITCODE_SUCCESS; }
/** * Opens the input file. * * @returns Command exit, error messages written using RTMsg*. * * @param pszFile The input filename. * @param pOpts The options, szOutput will be filled in by this * function on success. * @param phVfsIos Where to return the input stream handle. */ static RTEXITCODE gzipOpenInput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos) { int rc; pOpts->pszInput = pszFile; if (!strcmp(pszFile, "-")) { if ( !pOpts->fForce && pOpts->fDecompress && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT)) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Yeah, right. I'm not reading any compressed data from the terminal without --force.\n"); rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, true /*fLeaveOpen*/, phVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard input: %Rrc", rc); } else { const char *pszError; rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, phVfsIos, &pszError); if (RT_FAILURE(rc)) { if (pszError && *pszError) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsChainOpenIoStream failed with rc=%Rrc:\n" " '%s'\n" " %*s^\n", rc, pszFile, pszError - pszFile, ""); return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsChainOpenIoStream failed with rc=%Rrc: '%s'", rc, pszFile); } } return RTEXITCODE_SUCCESS; }
int main(int argc, char **argv) { int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); /* * Create a HTTP client instance. */ RTHTTP hHttp; rc = RTHttpCreate(&hHttp); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTHttpCreate failed: %Rrc", rc); /* * Parse arguments. */ static const RTGETOPTDEF s_aOptions[] = { { "--output", 'o', RTGETOPT_REQ_STRING }, { "--quiet", 'q', RTGETOPT_REQ_NOTHING }, { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, }; RTEXITCODE rcExit = RTEXITCODE_SUCCESS; const char *pszOutput = NULL; unsigned uVerbosityLevel = 1; RTGETOPTUNION ValueUnion; RTGETOPTSTATE GetState; RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); while ((rc = RTGetOpt(&GetState, &ValueUnion))) { switch (rc) { case 'o': pszOutput = ValueUnion.psz; break; case 'q': uVerbosityLevel--; break; case 'v': uVerbosityLevel++; break; case 'h': RTPrintf("Usage: %s [options] URL0 [URL1 [...]]\n" "\n" "Options:\n" " -o,--output=file\n" " Output file. If not given, the file is displayed on stdout.\n" " -q, --quiet\n" " -v, --verbose\n" " Controls the verbosity level.\n" " -h, -?, --help\n" " Display this help text and exit successfully.\n" " -V, --version\n" " Display the revision and exit successfully.\n" , RTPathFilename(argv[0])); return RTEXITCODE_SUCCESS; case 'V': RTPrintf("$Revision: 102641 $\n"); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: { int rcHttp; if (pszOutput && strcmp("-", pszOutput)) { if (uVerbosityLevel > 0) RTStrmPrintf(g_pStdErr, "Fetching '%s' into '%s'...\n", ValueUnion.psz, pszOutput); rcHttp = RTHttpGetFile(hHttp, ValueUnion.psz, pszOutput); } else { if (uVerbosityLevel > 0) RTStrmPrintf(g_pStdErr, "Fetching '%s'...\n", ValueUnion.psz); void *pvResp; size_t cbResp; rcHttp = RTHttpGetBinary(hHttp, ValueUnion.psz, &pvResp, &cbResp); if (RT_SUCCESS(rcHttp)) { RTVFSIOSTREAM hVfsIos; rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, 0, true /*fLeaveOpen*/, &hVfsIos); if (RT_SUCCESS(rc)) { rc = RTVfsIoStrmWrite(hVfsIos, pvResp, cbResp, true /*fBlocking*/, NULL); if (RT_FAILURE(rc)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error writing to stdout: %Rrc", rc); RTVfsIoStrmRelease(hVfsIos); } else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening stdout: %Rrc", rc); RTHttpFreeResponse(pvResp); } } if (RT_FAILURE(rcHttp)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error %Rrc getting '%s'", rcHttp, ValueUnion.psz); break; } default: return RTGetOptPrintError(rc, &ValueUnion); } } return rcExit; }
/** * Opens the input archive specified by the options. * * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + printed message. * @param pOpts The options. * @param phVfsFss Where to return the TAR filesystem stream handle. */ static RTEXITCODE rtZipTarCmdOpenInputArchive(PRTZIPTARCMDOPS pOpts, PRTVFSFSSTREAM phVfsFss) { int rc; /* * Open the input file. */ RTVFSIOSTREAM hVfsIos; if ( pOpts->pszFile && strcmp(pOpts->pszFile, "-") != 0) { const char *pszError; rc = RTVfsChainOpenIoStream(pOpts->pszFile, 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, pOpts->pszFile, pszError - pOpts->pszFile, ""); return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed with %Rrc opening the input archive '%s'", rc, pOpts->pszFile); } } else { rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/, &hVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to prepare standard in for reading: %Rrc", rc); } /* * Pass it thru a decompressor? */ RTVFSIOSTREAM hVfsIosDecomp = NIL_RTVFSIOSTREAM; switch (pOpts->chZipper) { /* no */ case '\0': rc = VINF_SUCCESS; break; /* gunzip */ case 'z': rc = RTZipGzipDecompressIoStream(hVfsIos, 0 /*fFlags*/, &hVfsIosDecomp); if (RT_FAILURE(rc)) RTMsgError("Failed to open gzip decompressor: %Rrc", rc); break; /* bunzip2 */ case 'j': rc = VERR_NOT_SUPPORTED; RTMsgError("bzip2 is not supported by this build"); break; /* bug */ default: rc = VERR_INTERNAL_ERROR_2; RTMsgError("unknown decompression method '%c'", pOpts->chZipper); break; } if (RT_FAILURE(rc)) { RTVfsIoStrmRelease(hVfsIos); return RTEXITCODE_FAILURE; } if (hVfsIosDecomp != NIL_RTVFSIOSTREAM) { RTVfsIoStrmRelease(hVfsIos); hVfsIos = hVfsIosDecomp; hVfsIosDecomp = NIL_RTVFSIOSTREAM; } /* * Open the filesystem stream. */ if (pOpts->enmFormat == RTZIPTARFORMAT_TAR) rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, phVfsFss); else if (pOpts->enmFormat == RTZIPTARFORMAT_XAR) #ifdef IPRT_WITH_XAR /* Requires C++ and XML, so only in some configruation of IPRT. */ rc = RTZipXarFsStreamFromIoStream(hVfsIos, 0/*fFlags*/, phVfsFss); #else rc = VERR_NOT_SUPPORTED; #endif else /** @todo make RTZipTarFsStreamFromIoStream fail if not tar file! */
/** * 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; }
/** * Handles a file on the command line. * * @returns exit code. * @param pszFile The file to handle. * @param fStdOut Whether to output to standard output or not. * @param fForce Whether to output to or input from terminals. * @param phVfsStdOut Pointer to the standard out handle. * (input/output) */ static RTEXITCODE gzipDecompressFile(const char *pszFile, bool fStdOut, bool fForce, PRTVFSIOSTREAM phVfsStdOut) { /* * Open the specified input file. */ const char *pszError; RTVFSIOSTREAM hVfsIn; int rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsIn, &pszError); if (RT_FAILURE(rc)) { if (pszError && *pszError) return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsChainOpenIoStream failed with rc=%Rrc:\n" " '%s'\n", " %*s^\n", rc, pszFile, pszError - pszFile, ""); return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsChainOpenIoStream failed with rc=%Rrc: '%s'", rc, pszFile); } /* * Output the output file. */ RTVFSIOSTREAM hVfsOut; char szFinal[RTPATH_MAX]; if (fStdOut) { if (*phVfsStdOut == NIL_RTVFSIOSTREAM) { rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, 0 /*fOpen*/, true /*fLeaveOpen*/, phVfsStdOut); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to set up standard out: %Rrc", rc); } hVfsOut = *phVfsStdOut; szFinal[0] = '\0'; } else { rc = RTStrCopy(szFinal, sizeof(szFinal), pszFile); /** @todo remove the extension? Or are we supposed * to get the org name from the gzip stream? */ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Decompressing to file is not implemented"); } /* * Do the decompressing, then flush and close the output stream (unless * it is stdout). */ RTEXITCODE rcExit = gzipDecompress(hVfsIn, hVfsOut); RTVfsIoStrmRelease(hVfsIn); rc = RTVfsIoStrmFlush(hVfsOut); if (RT_FAILURE(rc)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to flush the output file: %Rrc", rc); RTVfsIoStrmRelease(hVfsOut); /* * Remove the input file, if that's the desire of the caller, or * remove the output file on decompression failure. */ if (!fStdOut) { if (rcExit == RTEXITCODE_SUCCESS) { rc = RTFileDelete(pszFile); if (RT_FAILURE(rc)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileDelete failed with %rc: '%s'", rc, pszFile); } else { /* should we do this? */ rc = RTFileDelete(szFinal); if (RT_FAILURE(rc)) RTMsgError("RTFileDelete failed with %rc: '%s'", rc, pszFile); } } return rcExit; }