/** * 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 archive specified by the options. * * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + printed message. * @param pOpts The options. * @param phVfsFss Where to return the UNZIP filesystem stream handle. */ static RTEXITCODE rtZipUnzipCmdOpenInputArchive(PRTZIPUNZIPCMDOPS pOpts, PRTVFSFSSTREAM phVfsFss) { /* * Open the input file. */ RTVFSIOSTREAM hVfsIos; const char *pszError; int 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); } rc = RTZipPkzipFsStreamFromIoStream(hVfsIos, 0 /*fFlags*/, phVfsFss); RTVfsIoStrmRelease(hVfsIos); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open pkzip filesystem stream: %Rrc", rc); 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; }
/** * Adds a file to the manifest. * * @returns IPRT status code, failures with error message. * @param hManifest The manifest to add it to. * @param pszFilename The name of the file to add. * @param fAttr The manifest attributes to add. */ static int rtManifestAddFileToManifest(RTMANIFEST hManifest, const char *pszFilename, uint32_t fAttr) { RTVFSIOSTREAM hVfsIos; const char *pszError; int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, &hVfsIos, &pszError); if (RT_FAILURE(rc)) { if (pszError && *pszError) RTMsgError("RTVfsChainOpenIoStream failed with rc=%Rrc:\n" " '%s'\n", " %*s^\n", rc, pszFilename, pszError - pszFilename, ""); else RTMsgError("Failed with %Rrc opening '%s'", rc, pszFilename); return rc; } rc = RTManifestEntryAddIoStream(hManifest, hVfsIos, pszFilename, fAttr); if (RT_FAILURE(rc)) RTMsgError("RTManifestEntryAddIoStream failed for '%s': %Rrc", rc); RTVfsIoStrmRelease(hVfsIos); return rc; }
/** * 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! */
/** * 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; }