Created
February 21, 2014 17:59
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*******************************************************************//** | |
* @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: */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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!