VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/zip/gzipcmd.cpp

Last change on this file was 99013, checked in by vboxsync, 15 months ago

Fixed typo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
RevLine 
[33911]1/* $Id: gzipcmd.cpp 99013 2023-03-17 14:46:51Z vboxsync $ */
2/** @file
[34464]3 * IPRT - GZIP Utility.
[33911]4 */
5
6/*
[98103]7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
[33911]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
[33911]11 *
[96407]12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
[33911]25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
[96407]27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
[33911]29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
[96407]33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[33911]35 */
36
37
[69434]38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[33911]41#include <iprt/zip.h>
42
[33973]43#include <iprt/buildconfig.h>
[76346]44#include <iprt/err.h>
[33973]45#include <iprt/file.h>
[33911]46#include <iprt/getopt.h>
[33973]47#include <iprt/initterm.h>
[33911]48#include <iprt/message.h>
[33973]49#include <iprt/param.h>
[47359]50#include <iprt/path.h>
[33973]51#include <iprt/stream.h>
[33911]52#include <iprt/string.h>
53#include <iprt/vfs.h>
[33973]54#include <iprt/zip.h>
[33911]55
56
[69434]57/*********************************************************************************************************************************
58* Structures and Typedefs *
59*********************************************************************************************************************************/
[47359]60/**
61 * Gzip command options.
62 */
63typedef struct RTGZIPCMDOPTS
[33911]64{
[47359]65 bool fAscii;
66 bool fStdOut;
67 bool fDecompress;
68 bool fForce;
69 bool fKeep;
70 bool fList;
71 bool fName;
72 bool fQuiet;
73 bool fRecursive;
74 const char *pszSuff;
75 bool fTest;
76 unsigned uLevel;
77 /** The current output filename (for deletion). */
78 char szOutput[RTPATH_MAX];
79 /** The current input filename (for deletion and messages). */
80 const char *pszInput;
81} RTGZIPCMDOPTS;
[51519]82/** Pointer to GZIP options. */
[47359]83typedef RTGZIPCMDOPTS *PRTGZIPCMDOPTS;
[51519]84/** Pointer to const GZIP options. */
[47359]85typedef RTGZIPCMDOPTS const *PCRTGZIPCMDOPTS;
86
87
88
89/**
90 * Checks if the given standard handle is a TTY.
91 *
92 * @returns true / false
93 * @param enmStdHandle The standard handle.
94 */
95static bool gzipIsStdHandleATty(RTHANDLESTD enmStdHandle)
96{
97 /** @todo Add isatty() to IPRT. */
[62724]98 RT_NOREF1(enmStdHandle);
[33911]99 return false;
100}
101
[33973]102
103/**
104 * Pushes data from the input to the output I/O streams.
105 *
106 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
[47359]107 * @param hVfsSrc The source I/O stream.
108 * @param hVfsDst The destination I/O stream.
[33973]109 */
[47359]110static RTEXITCODE gzipPush(RTVFSIOSTREAM hVfsSrc, RTVFSIOSTREAM hVfsDst)
[33973]111{
112 for (;;)
113 {
114 uint8_t abBuf[_64K];
115 size_t cbRead;
[47359]116 int rc = RTVfsIoStrmRead(hVfsSrc, abBuf, sizeof(abBuf), true /*fBlocking*/, &cbRead);
[33973]117 if (RT_FAILURE(rc))
118 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmRead failed: %Rrc", rc);
119 if (rc == VINF_EOF && cbRead == 0)
120 return RTEXITCODE_SUCCESS;
121
[47359]122 rc = RTVfsIoStrmWrite(hVfsDst, abBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
[33973]123 if (RT_FAILURE(rc))
124 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmWrite failed: %Rrc", rc);
125 }
126}
127
[47359]128
129/**
130 * Pushes the bytes from the input to the output stream, flushes the output
131 * stream and closes both of them.
132 *
133 * On failure, we will delete the output file, if it's a file. The input file
134 * may be deleted, if we're not told to keep it (--keep, --to-stdout).
135 *
136 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
137 * @param phVfsSrc The input stream. Set to NIL if closed.
138 * @param pOpts The options.
139 * @param phVfsDst The output stream. Set to NIL if closed.
140 */
141static RTEXITCODE gzipPushFlushAndClose(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
[33973]142{
[47359]143 /*
144 * Push bytes, flush and close the streams.
145 */
146 RTEXITCODE rcExit = gzipPush(*phVfsSrc, *phVfsDst);
[33973]147
[47359]148 RTVfsIoStrmRelease(*phVfsSrc);
149 *phVfsSrc = NIL_RTVFSIOSTREAM;
[33973]150
[47359]151 int rc = RTVfsIoStrmFlush(*phVfsDst);
[49320]152 if (RT_FAILURE(rc) && rc != VERR_INVALID_PARAMETER)
[47359]153 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to flush the output file: %Rrc", rc);
154 RTVfsIoStrmRelease(*phVfsDst);
155 *phVfsDst = NIL_RTVFSIOSTREAM;
[33973]156
[47359]157 /*
158 * Do the cleaning up, if needed. Remove the input file, if that's the
159 * desire of the user, or remove the output file on failure.
160 */
161 if (!pOpts->fStdOut)
[33973]162 {
[47359]163 if (rcExit == RTEXITCODE_SUCCESS)
164 {
165 if (!pOpts->fKeep)
166 {
167 rc = RTFileDelete(pOpts->pszInput);
168 if (RT_FAILURE(rc))
169 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to delete '%s': %Rrc", pOpts->pszInput, rc);
170 }
171 }
172 else
173 {
174 rc = RTFileDelete(pOpts->szOutput);
175 if (RT_FAILURE(rc))
176 RTMsgError("Failed to delete '%s': %Rrc", pOpts->szOutput, rc);
177 }
[33973]178 }
[47359]179
[33973]180 return rcExit;
181}
182
183
184/**
[47359]185 * Compresses one stream to another.
[33973]186 *
[47359]187 * @returns Exit code.
188 * @param phVfsSrc The input stream. Set to NIL if closed.
189 * @param pOpts The options.
190 * @param phVfsDst The output stream. Set to NIL if closed.
[33973]191 */
[47359]192static RTEXITCODE gzipCompressFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
[33973]193{
194 /*
[99013]195 * Attach the compressor to the output stream.
[33973]196 */
[47359]197 RTVFSIOSTREAM hVfsGzip;
198 int rc = RTZipGzipCompressIoStream(*phVfsDst, 0 /*fFlags*/, pOpts->uLevel, &hVfsGzip);
[33973]199 if (RT_FAILURE(rc))
[47359]200 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTZipGzipCompressIoStream failed: %Rrc", rc);
[33973]201
[47359]202 uint32_t cRefs = RTVfsIoStrmRelease(*phVfsDst);
[62724]203 Assert(cRefs > 0); RT_NOREF_PV(cRefs);
[47359]204 *phVfsDst = hVfsGzip;
205
206 return gzipPushFlushAndClose(phVfsSrc, pOpts, phVfsDst);
207}
208
209
210/**
211 * Attach a decompressor to the given source stream, replacing and releasing the
212 * input handle with the decompressor.
213 *
214 * @returns Exit code.
215 * @param phVfsSrc The input stream. Replaced on success.
216 */
217static RTEXITCODE gzipSetupDecompressor(PRTVFSIOSTREAM phVfsSrc)
218{
[33973]219 /*
[47359]220 * Attach the decompressor to the input stream.
[33973]221 */
[49320]222 uint32_t fFlags = 0;
223 fFlags |= RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR;
[47359]224 RTVFSIOSTREAM hVfsGunzip;
[49320]225 int rc = RTZipGzipDecompressIoStream(*phVfsSrc, fFlags, &hVfsGunzip);
[47359]226 if (RT_FAILURE(rc))
227 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTZipGzipDecompressIoStream failed: %Rrc", rc);
228
229 uint32_t cRefs = RTVfsIoStrmRelease(*phVfsSrc);
[62724]230 Assert(cRefs > 0); RT_NOREF_PV(cRefs);
[47359]231 *phVfsSrc = hVfsGunzip;
232
[59755]233#if 0
234 /* This is a good place for testing stuff. */
235 rc = RTVfsCreateReadAheadForIoStream(*phVfsSrc, 0, 16, _4K+1, &hVfsGunzip);
236 AssertRC(rc);
237 if (RT_SUCCESS(rc))
238 {
239 uint32_t cRefs = RTVfsIoStrmRelease(*phVfsSrc);
240 Assert(cRefs > 0);
241 *phVfsSrc = hVfsGunzip;
242 }
243#endif
244
[47359]245 return RTEXITCODE_SUCCESS;
246}
247
248
249/**
250 * Decompresses one stream to another.
251 *
252 * @returns Exit code.
253 * @param phVfsSrc The input stream. Set to NIL if closed.
254 * @param pOpts The options.
255 * @param phVfsDst The output stream. Set to NIL if closed.
256 */
257static RTEXITCODE gzipDecompressFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
258{
259 RTEXITCODE rcExit = gzipSetupDecompressor(phVfsSrc);
260 if (rcExit == RTEXITCODE_SUCCESS)
261 rcExit = gzipPushFlushAndClose(phVfsSrc, pOpts, phVfsDst);
262 return rcExit;
263}
264
265
266/**
267 * For testing the archive (todo).
268 *
269 * @returns Exit code.
270 * @param phVfsSrc The input stream. Set to NIL if closed.
271 * @param pOpts The options.
272 */
273static RTEXITCODE gzipTestFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts)
274{
[62724]275 RT_NOREF_PV(pOpts);
276
[47359]277 /*
278 * Read the whole stream.
279 */
280 RTEXITCODE rcExit = gzipSetupDecompressor(phVfsSrc);
281 if (rcExit == RTEXITCODE_SUCCESS)
[33973]282 {
[47359]283 for (;;)
[33973]284 {
[47359]285 uint8_t abBuf[_64K];
286 size_t cbRead;
287 int rc = RTVfsIoStrmRead(*phVfsSrc, abBuf, sizeof(abBuf), true /*fBlocking*/, &cbRead);
[33973]288 if (RT_FAILURE(rc))
[47359]289 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmRead failed: %Rrc", rc);
290 if (rc == VINF_EOF && cbRead == 0)
291 return RTEXITCODE_SUCCESS;
[33973]292 }
293 }
[47359]294 return rcExit;
295}
296
297
298static RTEXITCODE gzipListFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts)
299{
[62724]300 RT_NOREF2(phVfsSrc, pOpts);
[47359]301 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Listing has not been implemented");
302}
303
304
305/**
306 * Opens the output file.
307 *
308 * @returns Command exit, error messages written using RTMsg*.
309 *
310 * @param pszFile The input filename.
311 * @param pOpts The options, szOutput will be filled in by this
312 * function on success.
313 * @param phVfsIos Where to return the output stream handle.
314 *
315 * @remarks This is actually not quite the way we need to do things.
316 *
317 * First of all, we need a GZIP file system stream for a real GZIP
318 * implementation, since there may be more than one file in the gzipped
319 * file.
320 *
321 * Second, we need to open the output files as we encounter files in the input
322 * file system stream. The gzip format contains timestamp and usually a
323 * filename, the default is to use this name (see the --no-name
324 * option).
325 */
326static RTEXITCODE gzipOpenOutput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos)
327{
328 int rc;
329 if (!strcmp(pszFile, "-") || pOpts->fStdOut)
[33973]330 {
[47359]331 strcpy(pOpts->szOutput, "-");
[33973]332
[47359]333 if ( !pOpts->fForce
334 && !pOpts->fDecompress
335 && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT))
336 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
337 "Yeah, right. I'm not writing any compressed data to the terminal without --force.\n");
[33973]338
[47359]339 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT,
340 RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
341 true /*fLeaveOpen*/,
342 phVfsIos);
343 if (RT_FAILURE(rc))
344 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard output: %Rrc", rc);
345 }
346 else
[33973]347 {
[47359]348 Assert(!RTVfsChainIsSpec(pszFile));
349
350 /* Construct an output filename. */
351 rc = RTStrCopy(pOpts->szOutput, sizeof(pOpts->szOutput), pszFile);
352 if (RT_FAILURE(rc))
353 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc);
354 if (pOpts->fDecompress)
[33973]355 {
[47359]356 /** @todo take filename from archive? */
357 size_t cchSuff = strlen(pOpts->pszSuff); Assert(cchSuff > 0);
358 size_t cch = strlen(pOpts->szOutput);
359 if ( cch <= cchSuff
360 || strcmp(&pOpts->szOutput[cch - cchSuff], pOpts->pszSuff))
361 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Input file does not end with: '%s'", pOpts->pszSuff);
362 pOpts->szOutput[cch - cchSuff] = '\0';
363 if (!RTPathFilename(pOpts->szOutput))
364 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: Input file name is all suffix.");
[33973]365 }
366 else
367 {
[47359]368 rc = RTStrCat(pOpts->szOutput, sizeof(pOpts->szOutput), pOpts->pszSuff);
[33973]369 if (RT_FAILURE(rc))
[47359]370 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: %Rrc", rc);
[33973]371 }
[47359]372
373 /* Open the output file. */
374 uint32_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;
375 if (pOpts->fForce)
376 fOpen |= RTFILE_O_CREATE_REPLACE;
377 else
378 fOpen |= RTFILE_O_CREATE;
379 rc = RTVfsIoStrmOpenNormal(pOpts->szOutput, fOpen, phVfsIos);
380 if (RT_FAILURE(rc))
381 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening output file '%s': %Rrc", pOpts->szOutput, rc);
[33973]382 }
383
[47359]384 return RTEXITCODE_SUCCESS;
[33973]385}
386
387
[47359]388/**
389 * Opens the input file.
390 *
391 * @returns Command exit, error messages written using RTMsg*.
392 *
393 * @param pszFile The input filename.
394 * @param pOpts The options, szOutput will be filled in by this
395 * function on success.
396 * @param phVfsIos Where to return the input stream handle.
397 */
398static RTEXITCODE gzipOpenInput(const char *pszFile, PRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsIos)
[33973]399{
[47359]400 int rc;
[33973]401
[47359]402 pOpts->pszInput = pszFile;
403 if (!strcmp(pszFile, "-"))
404 {
405 if ( !pOpts->fForce
406 && pOpts->fDecompress
407 && gzipIsStdHandleATty(RTHANDLESTD_OUTPUT))
408 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
409 "Yeah, right. I'm not reading any compressed data from the terminal without --force.\n");
[33973]410
[47359]411 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT,
412 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
413 true /*fLeaveOpen*/,
414 phVfsIos);
415 if (RT_FAILURE(rc))
416 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening standard input: %Rrc", rc);
417 }
418 else
419 {
[66602]420 uint32_t offError = 0;
421 RTERRINFOSTATIC ErrInfo;
422 rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE,
423 phVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
[47359]424 if (RT_FAILURE(rc))
[66602]425 return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core);
[47359]426 }
427
428 return RTEXITCODE_SUCCESS;
429
[33973]430}
431
432
[47359]433/**
434 * A mini GZIP program.
435 *
436 * @returns Program exit code.
437 *
438 * @param cArgs The number of arguments.
439 * @param papszArgs The argument vector. (Note that this may be
440 * reordered, so the memory must be writable.)
441 */
[70424]442RTDECL(RTEXITCODE) RTZipGzipCmd(unsigned cArgs, char **papszArgs)
[33911]443{
444
445 /*
446 * Parse the command line.
447 */
[33973]448 static const RTGETOPTDEF s_aOptions[] =
[33911]449 {
450 { "--ascii", 'a', RTGETOPT_REQ_NOTHING },
451 { "--stdout", 'c', RTGETOPT_REQ_NOTHING },
452 { "--to-stdout", 'c', RTGETOPT_REQ_NOTHING },
453 { "--decompress", 'd', RTGETOPT_REQ_NOTHING },
454 { "--uncompress", 'd', RTGETOPT_REQ_NOTHING },
455 { "--force", 'f', RTGETOPT_REQ_NOTHING },
[47359]456 { "--keep", 'k', RTGETOPT_REQ_NOTHING },
[33911]457 { "--list", 'l', RTGETOPT_REQ_NOTHING },
458 { "--no-name", 'n', RTGETOPT_REQ_NOTHING },
459 { "--name", 'N', RTGETOPT_REQ_NOTHING },
460 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
461 { "--recursive", 'r', RTGETOPT_REQ_NOTHING },
462 { "--suffix", 'S', RTGETOPT_REQ_STRING },
463 { "--test", 't', RTGETOPT_REQ_NOTHING },
464 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
465 { "--fast", '1', RTGETOPT_REQ_NOTHING },
466 { "-1", '1', RTGETOPT_REQ_NOTHING },
467 { "-2", '2', RTGETOPT_REQ_NOTHING },
468 { "-3", '3', RTGETOPT_REQ_NOTHING },
469 { "-4", '4', RTGETOPT_REQ_NOTHING },
470 { "-5", '5', RTGETOPT_REQ_NOTHING },
471 { "-6", '6', RTGETOPT_REQ_NOTHING },
472 { "-7", '7', RTGETOPT_REQ_NOTHING },
473 { "-8", '8', RTGETOPT_REQ_NOTHING },
474 { "-9", '9', RTGETOPT_REQ_NOTHING },
475 { "--best", '9', RTGETOPT_REQ_NOTHING }
476 };
477
[47359]478 RTGZIPCMDOPTS Opts;
479 Opts.fAscii = false;
480 Opts.fStdOut = false;
481 Opts.fDecompress = false;
482 Opts.fForce = false;
483 Opts.fKeep = false;
484 Opts.fList = false;
485 Opts.fName = true;
486 Opts.fQuiet = false;
487 Opts.fRecursive = false;
488 Opts.pszSuff = ".gz";
489 Opts.fTest = false;
490 Opts.uLevel = 6;
[33911]491
492 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
493 unsigned cProcessed = 0;
[62724]494 //RTVFSIOSTREAM hVfsStdOut= NIL_RTVFSIOSTREAM;
[33911]495
[33973]496 RTGETOPTSTATE GetState;
[47359]497 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
498 RTGETOPTINIT_FLAGS_OPTS_FIRST);
499 if (RT_FAILURE(rc))
500 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);
501
[33911]502 for (;;)
503 {
504 RTGETOPTUNION ValueUnion;
[47359]505 int chOpt = RTGetOpt(&GetState, &ValueUnion);
506 switch (chOpt)
[33911]507 {
508 case 0:
509 /*
510 * If we've processed any files we're done. Otherwise take
511 * input from stdin and write the output to stdout.
512 */
[33973]513 if (cProcessed > 0)
[33911]514 return rcExit;
[47359]515 ValueUnion.psz = "-";
516 Opts.fStdOut = true;
[69046]517 RT_FALL_THRU();
[33911]518 case VINF_GETOPT_NOT_OPTION:
519 {
[47359]520 if (!*Opts.pszSuff && !Opts.fStdOut)
[33973]521 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --suffix option specified an empty string");
[47359]522 if (!Opts.fStdOut && RTVfsChainIsSpec(ValueUnion.psz))
[33973]523 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Must use standard out with VFS chain specifications");
[66595]524 if ( Opts.fName
525 && !Opts.fList
526 && !Opts.fTest
527 && !Opts.fDecompress)
[47359]528 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --name option has not yet been implemented. Use --no-name.");
529 if (Opts.fAscii)
530 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --ascii option has not yet been implemented.");
531 if (Opts.fRecursive)
532 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --recursive option has not yet been implemented.");
[33911]533
[47359]534 /* Open the input file. */
535 RTVFSIOSTREAM hVfsSrc;
536 RTEXITCODE rcExit2 = gzipOpenInput(ValueUnion.psz, &Opts, &hVfsSrc);
537 if (rcExit2 == RTEXITCODE_SUCCESS)
538 {
539 if (Opts.fList)
540 rcExit2 = gzipListFile(&hVfsSrc, &Opts);
541 else if (Opts.fTest)
542 rcExit2 = gzipTestFile(&hVfsSrc, &Opts);
543 else
544 {
545 RTVFSIOSTREAM hVfsDst;
546 rcExit2 = gzipOpenOutput(ValueUnion.psz, &Opts, &hVfsDst);
547 if (rcExit2 == RTEXITCODE_SUCCESS)
548 {
549 if (Opts.fDecompress)
550 rcExit2 = gzipDecompressFile(&hVfsSrc, &Opts, &hVfsDst);
551 else
552 rcExit2 = gzipCompressFile(&hVfsSrc, &Opts, &hVfsDst);
553 RTVfsIoStrmRelease(hVfsDst);
554 }
555 }
556 RTVfsIoStrmRelease(hVfsSrc);
557 }
[33973]558 if (rcExit2 != RTEXITCODE_SUCCESS)
559 rcExit = rcExit2;
560
[33911]561 cProcessed++;
562 break;
563 }
564
[47359]565 case 'a': Opts.fAscii = true; break;
566 case 'c':
567 Opts.fStdOut = true;
568 Opts.fKeep = true;
569 break;
570 case 'd': Opts.fDecompress = true; break;
571 case 'f': Opts.fForce = true; break;
572 case 'k': Opts.fKeep = true; break;
573 case 'l': Opts.fList = true; break;
574 case 'n': Opts.fName = false; break;
575 case 'N': Opts.fName = true; break;
576 case 'q': Opts.fQuiet = true; break;
577 case 'r': Opts.fRecursive = true; break;
578 case 'S': Opts.pszSuff = ValueUnion.psz; break;
579 case 't': Opts.fTest = true; break;
580 case 'v': Opts.fQuiet = false; break;
581 case '1': Opts.uLevel = 1; break;
582 case '2': Opts.uLevel = 2; break;
583 case '3': Opts.uLevel = 3; break;
584 case '4': Opts.uLevel = 4; break;
585 case '5': Opts.uLevel = 5; break;
586 case '6': Opts.uLevel = 6; break;
587 case '7': Opts.uLevel = 7; break;
588 case '8': Opts.uLevel = 8; break;
589 case '9': Opts.uLevel = 9; break;
[33911]590
[33973]591 case 'h':
592 RTPrintf("Usage: to be written\nOption dump:\n");
593 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
594 RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
595 return RTEXITCODE_SUCCESS;
596
597 case 'V':
598 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
599 return RTEXITCODE_SUCCESS;
600
[33911]601 default:
[47359]602 return RTGetOptPrintError(chOpt, &ValueUnion);
[33911]603 }
604 }
605}
606
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use