tarcmd.cpp revision 4eb5a468e1ff750304441e03d1b2311ce049956a
/* $Id$ */
/** @file
* IPRT - TAR Command.
*/
/*
* Copyright (C) 2010 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>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#define RTZIPTARCMD_OPT_DELETE 1000
#define RTZIPTARCMD_OPT_OWNER 1001
#define RTZIPTARCMD_OPT_GROUP 1002
#define RTZIPTARCMD_OPT_PREFIX 1003
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* IPT TAR option structure.
*/
typedef struct RTZIPTARCMDOPS
{
/** The operation (Acdrtux or RTZIPTARCMD_OPT_DELETE). */
int iOperation;
/** The long operation option name. */
const char *pszOperation;
/** The directory to change into when packing and unpacking. */
const char *pszDirectory;
/** The tar file name. */
const char *pszFile;
/** Whether we're verbose or quiet. */
bool fVerbose;
/** Whether to preserve permissions when restoring. */
bool fPreservePermissions;
/** The compressor/decompressor method to employ (0, z or j). */
char chZipper;
/** The owner to set. */
const char *pszOwner;
/** The owner ID to set when unpacking if pszOwner is not NULL. */
/** The group to set. */
const char *pszGroup;
/** The group ID to set when unpacking if pszGroup is not NULL. */
/** What to prefix all names with when creating, adding, whatever. */
const char *pszPrefix;
/** The number of files(, directories or whatever) specified. */
/** Array of files(, directories or whatever).
* Terminated by a NULL entry. */
const char * const *papszFiles;
/** Pointer to the IPRT tar options. */
typedef RTZIPTARCMDOPS *PRTZIPTARCMDOPS;
/**
* Checks if @a pszName is a member of @a papszNames, optionally returning the
* index.
*
* @returns true if the name is in the list, otherwise false.
* @param pszName The name to find.
* @param papszNames The array of names.
* @param piName Where to optionally return the array index.
*/
static bool rtZipTarCmdIsNameInArray(const char *pszName, const char * const *papszNames, uint32_t *piName)
{
{
if (piName)
return true;
}
return false;
}
/**
* 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.
*/
{
int rc;
/*
* Open the input file.
*/
{
const char *pszError;
&hVfsIos,
&pszError);
if (RT_FAILURE(rc))
{
return RTMsgErrorExit(RTEXITCODE_FAILURE,
"RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
" '%s'\n",
" %*s^\n",
return RTMsgErrorExit(RTEXITCODE_FAILURE,
}
}
else
{
true /*fLeaveOpen*/,
&hVfsIos);
if (RT_FAILURE(rc))
}
/*
* Pass it thru a decompressor?
*/
{
/* no */
case '\0':
rc = VINF_SUCCESS;
break;
/* gunzip */
case 'z':
if (RT_FAILURE(rc))
break;
/* bunzip2 */
case 'j':
RTMsgError("bzip2 is not supported by this build");
break;
/* bug */
default:
break;
}
if (RT_FAILURE(rc))
{
return RTEXITCODE_FAILURE;
}
if (hVfsIosDecomp != NIL_RTVFSIOSTREAM)
{
}
/*
* Open the tar filesystem stream.
*/
if (RT_FAILURE(rc))
return RTEXITCODE_SUCCESS;
}
/**
* Display a tar entry in the verbose form.
*
* @returns rcExit or RTEXITCODE_FAILURE.
* @param rcExit The current exit code.
* @param hVfsObj The tar object to display
* @param pszName The name.
*/
static RTEXITCODE rtZipTarCmdDisplayEntryVerbose(RTEXITCODE rcExit, RTVFSOBJ hVfsObj, const char *pszName)
{
/*
* Query all the information.
*/
if (RT_FAILURE(rc))
{
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo returned %Rrc on '%s'", rc, pszName);
}
if (RT_FAILURE(rc))
{
"RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
}
if (RT_FAILURE(rc))
{
"RTVfsObjQueryInfo(,,UNIX_OWNER) returned %Rrc on '%s'",
}
/*
* Translate the mode mask.
*/
char szMode[16];
{
default: szMode[0] = '?'; break;
}
/*
* Make sure we've got valid owner and group strings.
*/
/*
* Format the modification time.
*/
char szModTime[32];
/*
* Format the size and figure how much space is needed between the
*/
char szSize[64];
+ 1
: 0;
/*
* Go to press.
*/
RTPrintf("%s %s/%s%*s %s %s %s\n",
cchPad, "",
pszName);
return rcExit;
}
/**
* Implements the -t/--list operation.
*
* @returns The appropriate exit code.
* @param pOpts The tar options.
*/
{
/*
* Allocate a bitmap to go with the file list. This will be used to
* indicate which files we've processed and which not.
*/
{
if (!pbmFound)
}
/*
* Open the input archive.
*/
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Process the stream.
*/
for (;;)
{
/*
* Retrive the next object.
*/
char *pszName;
if (RT_FAILURE(rc))
{
break;
}
/*
* Should we display this entry?
*/
{
if (pbmFound)
else
}
/*
* Release the current object and string.
*/
}
/*
* Complain about any files we didn't find.
*/
{
}
}
return rcExit;
}
{
/*
* Parse the command line.
*
* N.B. This is less flexible that your regular tar program in that it
* requires the operation to be specified as an option. On the other
* hand, you can specify it where ever you like in the command line.
*/
static const RTGETOPTDEF s_aOptions[] =
{
/* operations */
/* basic options */
/* other options. */
/* IPRT extensions */
};
if (RT_FAILURE(rc))
&& rc != VINF_GETOPT_NOT_OPTION)
{
switch (rc)
{
/* operations */
case 'A':
case 'c':
case 'd':
case 'r':
case 't':
case 'u':
case 'x':
case RTZIPTARCMD_OPT_DELETE:
if (Opts.iOperation)
break;
/* basic options */
case 'C':
if (Opts.pszDirectory)
break;
case 'f':
break;
case 'v':
break;
case 'p':
Opts.fPreservePermissions = true;
break;
case 'j':
case 'z':
break;
case RTZIPTARCMD_OPT_OWNER:
break;
case RTZIPTARCMD_OPT_GROUP:
break;
/* iprt extensions */
case RTZIPTARCMD_OPT_PREFIX:
break;
case 'h':
RTPrintf("Usage: to be written\nOption dump:\n");
for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
else
return RTEXITCODE_SUCCESS;
case 'V':
return RTEXITCODE_SUCCESS;
default:
}
}
if (rc == VINF_GETOPT_NOT_OPTION)
{
/* this is kind of ugly. */
}
/*
* Post proceess the options.
*/
if (Opts.iOperation == 0)
{
}
return RTMsgErrorExit(RTEXITCODE_FAILURE, "The use of --owner with %s has not implemented yet", Opts.pszOperation);
return RTMsgErrorExit(RTEXITCODE_FAILURE, "The use of --group with %s has not implemented yet", Opts.pszOperation);
/*
* Do the job.
*/
switch (Opts.iOperation)
{
case 't':
return rtZipTarCmdList(&Opts);
case 'A':
case 'c':
case 'd':
case 'r':
case 'u':
case 'x':
case RTZIPTARCMD_OPT_DELETE:
return RTMsgErrorExit(RTEXITCODE_FAILURE, "The operation %s is not implemented yet", Opts.pszOperation);
default:
}
}