Skip to content

Instantly share code, notes, and snippets.

@LeSpocky
Created February 21, 2014 17:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LeSpocky/9139549 to your computer and use it in GitHub Desktop.
Save LeSpocky/9139549 to your computer and use it in GitHub Desktop.
an example for a complete zlib wrapper for libtar using C++ vectors for associating zlib file handles to libtar file descriptors
/*******************************************************************//**
* @file tlue_tar.cpp
*
* Test libtar.
*
* @author Alexander Dahl <post@lespocky.de>
* @date Created: 2014-02-21
*
* Copyright 2014 Alexander Dahl
**********************************************************************/
#include "tlue_tar.hpp"
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libtar.h>
#include <zlib.h>
#include "tlue.h"
/* declarations */
static int gzopen_frontend( const char *pathname, int flags, mode_t mode );
static int gzclose_frontend( int fd );
static ssize_t gzread_frontend( int fd, void *buf, size_t count );
static ssize_t gzwrite_frontend( int fd, const void *buf, size_t count );
/* globals */
std::vector<gzFile> gz_files;
tartype_t gz_type = { (openfunc_t) gzopen_frontend, gzclose_frontend,
gzread_frontend, gzwrite_frontend };
/* definitions */
int cmd_tar( int aargc, char **aargv ) {
char tmpname[] = "/tmp/tlueXXXXXX";
char savename[] = "foo";
int fd, rv = TLUE_ERR_NONE;
FILE *fh = NULL;
TAR *t = NULL;
/* check number of parameters */
if ( aargc - optind != 2 ) {
(void) fprintf( stderr,
_("Wrong number of parameters. See help for more info!\n") );
return TLUE_ERR_PARAM_COUNT;
}
/* create temporary file */
if ( (fd = mkstemp( tmpname )) == -1 ) {
(void) fprintf( stderr, "%s (%s)\n",
_("Could not create temporary file!"), strerror( errno ) );
return TLUE_ERR_SYSTEM;
}
fh = fdopen( fd, "w" );
if ( fh == NULL ) {
(void) fprintf( stderr, "%s (%s)\n",
_("Error opening file stream!"), strerror( errno ) );
rv = TLUE_ERR_SYSTEM;
goto leave_cmd_tar;
}
/* write to file */
if ( fputs( "foo\n", fh ) == EOF ) {
(void) fputs( _("Error writing to file!\n"), stderr );
rv = TLUE_ERR_SYSTEM;
goto leave_cmd_tar;
}
/* close file, but do not remove yet, we have to append it to the
* tar archive! */
if ( fclose( fh ) ) {
(void) fprintf( stderr, "%s (%s)\n",
_("Error closing temporary file!"), strerror( errno ) );
}
fh = NULL; /* prevent from double fclose call */
/* open new tar file */
/* TODO make gzip optional */
if ( tar_open( &t, aargv[optind+1], &gz_type, O_WRONLY | O_CREAT,
0644, TAR_GNU ) )
{
(void) fputs( _("Error opening new tar file!"), stderr );
rv = TLUE_ERR_LIBTAR;
goto leave_cmd_tar;
}
/* add file to tar archive */
if ( tar_append_file( t, tmpname, savename ) ) {
(void) fputs( _("Could not append file to tar archive!"), stderr );
rv = TLUE_ERR_LIBTAR;
goto leave_cmd_tar;
}
/* append EOF to tar archive */
if ( tar_append_eof( t ) ) {
(void) fputs( _("Could not append EOF to tar archive!"), stderr );
rv = TLUE_ERR_LIBTAR;
goto leave_cmd_tar;
}
leave_cmd_tar:
if ( t != NULL ) {
if ( tar_close( t ) ) {
(void) fputs( _("Error closing tar archive!\n"), stderr );
}
}
if ( fh != NULL ) {
if ( fclose( fh ) != 0 ) {
(void) fprintf( stderr, "%s (%s)\n",
_("Error closing file!"), strerror( errno ) );
rv = TLUE_ERR_SYSTEM;
}
}
if ( remove( tmpname ) != 0 ) {
(void) fprintf( stderr, "%s (%s)\n", _("Error removing file!"),
strerror( errno ) );
rv = TLUE_ERR_SYSTEM;
}
return rv;
}
int gzopen_frontend( const char *pathname, int flags, mode_t mode ) {
char *gz_flags = NULL;
int fd, rv;
gzFile gzf;
/* create flags needed by zlib from flags used with open() */
switch ( flags & O_ACCMODE ) {
case O_WRONLY:
gz_flags = strdup( "wb" );
if ( gz_flags == NULL ) return -1;
break;
case O_RDONLY:
gz_flags = strdup( "rb" );
if ( gz_flags == NULL ) return -1;
break;
default:
case O_RDWR:
errno = EINVAL;
return -1;
}
/* however open file with flags passed by the user */
fd = open( pathname, flags, mode );
if ( fd == -1 ) {
rv = -1;
goto leave_gzopen_frontend;
}
/* and now zlib */
gzf = gzdopen( fd, gz_flags );
if ( gzf == NULL ) {
(void) close( fd );
rv = -1;
goto leave_gzopen_frontend;
}
gz_files.push_back( gzf );
rv = gz_files.size();
leave_gzopen_frontend:
if ( gz_flags ) free( gz_flags );
return rv;
}
int gzclose_frontend( int fd ) {
int rv;
gzFile gzf;
/* checks */
if ( gz_files.empty() ) {
errno = EBADF;
return -1;
}
if ( fd > gz_files.size() ) {
errno = EINVAL;
return -1;
}
/* call zlib */
rv = gzclose( gz_files[fd-1] );
/* remove gzFile* association from our list */
gz_files.pop_back();
return rv ? -1 : 0;
}
ssize_t gzread_frontend( int fd, void *buf, size_t count ) {
if ( gz_files.empty() ) {
errno = EBADF;
return -1;
}
if ( fd > gz_files.size() ) {
errno = EINVAL;
return -1;
}
return gzread( gz_files[fd-1], buf, count );
}
ssize_t gzwrite_frontend( int fd, const void *buf, size_t count ) {
int rv;
if ( gz_files.empty() ) {
errno = EBADF;
return -1;
}
if ( fd > gz_files.size() ) {
errno = EINVAL;
return -1;
}
/* yes, _this_ zlib function returns 0 on error and number of
* uncompressed bytes instead */
rv = gzwrite( gz_files[fd-1], buf, count );
if ( rv <= 0 ) {
return -1;
} else {
return rv;
}
}
/* vim: set noet sts=0 ts=4 sw=4 sr: */
@loicmorvan
Copy link

Isn't the line 200 wrong? It should just nullify the item (fd - 1) otherwise the indexes won't match for other files.

You use only one file at a time, so it does not generate a bug in your case, but still.

Thank you for this sample!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment