RTGzip.cpp revision b709d369e289514c1af16ed380f79292be695aff
/* $Id$ */
/** @file
* IPRT - GZIP Utility.
*/
/*
* Copyright (C) 2010-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/buildconfig.h>
#include <iprt/initterm.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Gzip command options.
*/
typedef struct RTGZIPCMDOPTS
{
bool fAscii;
bool fStdOut;
bool fDecompress;
bool fForce;
bool fKeep;
bool fList;
bool fName;
bool fQuiet;
bool fRecursive;
const char *pszSuff;
bool fTest;
unsigned uLevel;
/** The current output filename (for deletion). */
char szOutput[RTPATH_MAX];
/** The current input filename (for deletion and messages). */
const char *pszInput;
/** Pointer to GZIP options. */
typedef RTGZIPCMDOPTS *PRTGZIPCMDOPTS;
/** Pointer to const GZIP options. */
typedef RTGZIPCMDOPTS const *PCRTGZIPCMDOPTS;
/**
* Checks if the given standard handle is a TTY.
*
* @returns true / false
* @param enmStdHandle The standard handle.
*/
{
/** @todo Add isatty() to IPRT. */
return false;
}
/**
* Pushes data from the input to the output I/O streams.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
* @param hVfsSrc The source I/O stream.
* @param hVfsDst The destination I/O stream.
*/
{
for (;;)
{
if (RT_FAILURE(rc))
return RTEXITCODE_SUCCESS;
if (RT_FAILURE(rc))
}
}
/**
* Pushes the bytes from the input to the output stream, flushes the output
* stream and closes both of them.
*
* On failure, we will delete the output file, if it's a file. The input file
* may be deleted, if we're not told to keep it (--keep, --to-stdout).
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
* @param phVfsSrc The input stream. Set to NIL if closed.
* @param pOpts The options.
* @param phVfsDst The output stream. Set to NIL if closed.
*/
static RTEXITCODE gzipPushFlushAndClose(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
{
/*
* Push bytes, flush and close the streams.
*/
/*
* Do the cleaning up, if needed. Remove the input file, if that's the
* desire of the user, or remove the output file on failure.
*/
{
if (rcExit == RTEXITCODE_SUCCESS)
{
{
if (RT_FAILURE(rc))
}
}
else
{
if (RT_FAILURE(rc))
}
}
return rcExit;
}
/**
* Compresses one stream to another.
*
* @returns Exit code.
* @param phVfsSrc The input stream. Set to NIL if closed.
* @param pOpts The options.
* @param phVfsDst The output stream. Set to NIL if closed.
*/
static RTEXITCODE gzipCompressFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
{
/*
* Attach the ompressor to the output stream.
*/
if (RT_FAILURE(rc))
}
/**
* Attach a decompressor to the given source stream, replacing and releasing the
* input handle with the decompressor.
*
* @returns Exit code.
* @param phVfsSrc The input stream. Replaced on success.
*/
{
/*
* Attach the decompressor to the input stream.
*/
if (RT_FAILURE(rc))
*phVfsSrc = hVfsGunzip;
return RTEXITCODE_SUCCESS;
}
/**
* Decompresses one stream to another.
*
* @returns Exit code.
* @param phVfsSrc The input stream. Set to NIL if closed.
* @param pOpts The options.
* @param phVfsDst The output stream. Set to NIL if closed.
*/
static RTEXITCODE gzipDecompressFile(PRTVFSIOSTREAM phVfsSrc, PCRTGZIPCMDOPTS pOpts, PRTVFSIOSTREAM phVfsDst)
{
if (rcExit == RTEXITCODE_SUCCESS)
return rcExit;
}
/**
* For testing the archive (todo).
*
* @returns Exit code.
* @param phVfsSrc The input stream. Set to NIL if closed.
* @param pOpts The options.
*/
{
/*
* Read the whole stream.
*/
if (rcExit == RTEXITCODE_SUCCESS)
{
for (;;)
{
if (RT_FAILURE(rc))
return RTEXITCODE_SUCCESS;
}
}
return rcExit;
}
{
}
/**
* 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;
{
&& !pOpts->fDecompress
return RTMsgErrorExit(RTEXITCODE_SYNTAX,
"Yeah, right. I'm not writing any compressed data to the terminal without --force.\n");
true /*fLeaveOpen*/,
phVfsIos);
if (RT_FAILURE(rc))
}
else
{
/* Construct an output filename. */
if (RT_FAILURE(rc))
if (pOpts->fDecompress)
{
/** @todo take filename from archive? */
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing output filename: Input file name is all suffix.");
}
else
{
if (RT_FAILURE(rc))
}
/* Open the output file. */
else
fOpen |= RTFILE_O_CREATE;
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening output file '%s': %Rrc", pOpts->szOutput, 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.
*/
{
int rc;
{
&& pOpts->fDecompress
return RTMsgErrorExit(RTEXITCODE_SYNTAX,
"Yeah, right. I'm not reading any compressed data from the terminal without --force.\n");
true /*fLeaveOpen*/,
phVfsIos);
if (RT_FAILURE(rc))
}
else
{
const char *pszError;
rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, phVfsIos, &pszError);
if (RT_FAILURE(rc))
{
return RTMsgErrorExit(RTEXITCODE_FAILURE,
"RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
" '%s'\n",
" %*s^\n",
return RTMsgErrorExit(RTEXITCODE_FAILURE,
"RTVfsChainOpenIoStream failed with rc=%Rrc: '%s'",
}
}
return RTEXITCODE_SUCCESS;
}
/**
* A mini GZIP program.
*
* @returns Program exit code.
*
* @param cArgs The number of arguments.
* @param papszArgs The argument vector. (Note that this may be
* reordered, so the memory must be writable.)
*/
{
/*
* Parse the command line.
*/
static const RTGETOPTDEF s_aOptions[] =
{
};
Opts.fDecompress = false;
Opts.fRecursive = false;
unsigned cProcessed = 0;
if (RT_FAILURE(rc))
for (;;)
{
switch (chOpt)
{
case 0:
/*
* If we've processed any files we're done. Otherwise take
* input from stdin and write the output to stdout.
*/
if (cProcessed > 0)
return rcExit;
/* Fall thru. */
case VINF_GETOPT_NOT_OPTION:
{
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The --name option has not yet been implemented. Use --no-name.");
if (Opts.fRecursive)
/* Open the input file. */
if (rcExit2 == RTEXITCODE_SUCCESS)
{
else
{
if (rcExit2 == RTEXITCODE_SUCCESS)
{
if (Opts.fDecompress)
else
}
}
}
if (rcExit2 != RTEXITCODE_SUCCESS)
cProcessed++;
break;
}
case 'c':
break;
case 'h':
RTPrintf("Usage: to be written\nOption dump:\n");
for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
return RTEXITCODE_SUCCESS;
case 'V':
return RTEXITCODE_SUCCESS;
default:
}
}
}
{
if (RT_FAILURE(rc))
return RTMsgInitFailure(rc);
}