blob: b50934935ddfe8ed302b4ae30402fe10d0245df1 [file] [log] [blame]
/*
** Copyright 1998-2003 University of Illinois Board of Trustees
** Copyright 1998-2003 Mark D. Roth
** All rights reserved.
**
** libtar.c - demo driver program for libtar
**
** Mark D. Roth <roth@uiuc.edu>
** Campus Information Technologies and Educational Services
** University of Illinois at Urbana-Champaign
*/
#include <libtar/config.h>
#include <libtar/libtar.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <libtar/compat.h>
#include <io.h>
#else
#include <sys/param.h>
#endif
#ifdef STDC_HEADERS
# include <string.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
# include <stdlib.h>
#endif
#ifdef DEBUG
# include <signal.h>
#endif
#include CMTAR_ZLIB_HEADER
#include <libtar/compat.h>
char *progname;
int verbose = 0;
int use_gnu = 0;
#ifdef DEBUG
void
segv_handler(int sig)
{
puts("OOPS! Caught SIGSEGV, bailing out...");
fflush(stdout);
fflush(stderr);
}
#endif
#ifdef HAVE_LIBZ
int use_zlib = 0;
struct gzStruct
{
gzFile* GZFile;
};
struct gzStruct GZStruct;
#if defined ( _MSC_VER) || defined(__WATCOMC__)
#include <io.h>
//Yogi: hack. this should work on windows where there is no O_ACCMODE defined
#ifndef O_ACCMODE
# define O_ACCMODE 0x0003
#endif
#endif
static int libtar_gzopen(void* call_data, const char *pathname,
int oflags, mode_t mode)
{
char *gzoflags;
int fd;
struct gzStruct* gzf = (struct gzStruct*)call_data;
switch (oflags & O_ACCMODE)
{
case O_WRONLY:
gzoflags = "wb";
break;
case O_RDONLY:
gzoflags = "rb";
break;
default:
case O_RDWR:
errno = EINVAL;
return -1;
}
fd = open(pathname, oflags, mode);
if (fd == -1)
{
return -1;
}
#if defined(__BEOS__) && !defined(__ZETA__) /* no fchmod on BeOS...do pathname instead. */
if ((oflags & O_CREAT) && chmod(pathname, mode & 07777))
{
return -1;
}
#elif !defined(_WIN32) || defined(__CYGWIN__)
if ((oflags & O_CREAT) && fchmod(fd, mode & 07777))
{
return -1;
}
#endif
gzf->GZFile = gzdopen(fd, gzoflags);
if (!gzf->GZFile)
{
errno = ENOMEM;
return -1;
}
return fd;
}
static int libtar_gzclose(void* call_data)
{
struct gzStruct* gzf = (struct gzStruct*)call_data;
return gzclose(gzf->GZFile);
}
static ssize_t libtar_gzread(void* call_data, void* buf, size_t count)
{
struct gzStruct* gzf = (struct gzStruct*)call_data;
return gzread(gzf->GZFile, buf, (unsigned int)count);
}
static ssize_t libtar_gzwrite(void* call_data, const void* buf, size_t count)
{
struct gzStruct* gzf = (struct gzStruct*)call_data;
return gzwrite(gzf->GZFile, (void*)buf, (unsigned int)count);
}
tartype_t gztype = {
libtar_gzopen,
libtar_gzclose,
libtar_gzread,
libtar_gzwrite,
&GZStruct
};
#endif /* HAVE_LIBZ */
static int
create(char *tarfile, char *rootdir, libtar_list_t *l)
{
TAR *t;
char *pathname;
char buf[TAR_MAXPATHLEN];
libtar_listptr_t lp;
if (tar_open(&t, tarfile,
#ifdef HAVE_LIBZ
(use_zlib ? &gztype : NULL),
#else
NULL,
#endif
O_WRONLY | O_CREAT, 0644,
(verbose ? TAR_VERBOSE : 0)
| (use_gnu ? TAR_GNU : 0)) == -1)
{
fprintf(stderr, "tar_open(): %s\n", strerror(errno));
return -1;
}
libtar_listptr_reset(&lp);
while (libtar_list_next(l, &lp) != 0)
{
pathname = (char *)libtar_listptr_data(&lp);
if (pathname[0] != '/' && rootdir != NULL)
snprintf(buf, sizeof(buf), "%s/%s", rootdir, pathname);
else
strlcpy(buf, pathname, sizeof(buf));
if (tar_append_tree(t, buf, pathname) != 0)
{
fprintf(stderr,
"tar_append_tree(\"%s\", \"%s\"): %s\n", buf,
pathname, strerror(errno));
tar_close(t);
return -1;
}
}
if (tar_append_eof(t) != 0)
{
fprintf(stderr, "tar_append_eof(): %s\n", strerror(errno));
tar_close(t);
return -1;
}
if (tar_close(t) != 0)
{
fprintf(stderr, "tar_close(): %s\n", strerror(errno));
return -1;
}
return 0;
}
static int
list(char *tarfile)
{
TAR *t;
int i;
if (tar_open(&t, tarfile,
#ifdef HAVE_LIBZ
(use_zlib ? &gztype : NULL),
#else
NULL,
#endif
O_RDONLY, 0,
(verbose ? TAR_VERBOSE : 0)
| (use_gnu ? TAR_GNU : 0)) == -1)
{
fprintf(stderr, "tar_open(): %s\n", strerror(errno));
return -1;
}
while ((i = th_read(t)) == 0)
{
th_print_long_ls(t);
#ifdef DEBUG
th_print(t);
#endif
if (TH_ISREG(t) && tar_skip_regfile(t) != 0)
{
fprintf(stderr, "tar_skip_regfile(): %s\n",
strerror(errno));
return -1;
}
}
#ifdef DEBUG
printf("th_read() returned %d\n", i);
printf("EOF mark encountered after %ld bytes\n",
# ifdef HAVE_LIBZ
(use_zlib
? gzseek((gzFile) t->fd, 0, SEEK_CUR)
:
# endif
lseek(t->fd, 0, SEEK_CUR)
# ifdef HAVE_LIBZ
)
# endif
);
#endif
if (tar_close(t) != 0)
{
fprintf(stderr, "tar_close(): %s\n", strerror(errno));
return -1;
}
(void)i;
return 0;
}
static int
extract(char *tarfile, char *rootdir)
{
TAR *t;
#ifdef DEBUG
puts("opening tarfile...");
#endif
if (tar_open(&t, tarfile,
#ifdef HAVE_LIBZ
(use_zlib ? &gztype : NULL),
#else
NULL,
#endif
O_RDONLY, 0,
(verbose ? TAR_VERBOSE : 0)
| (use_gnu ? TAR_GNU : 0)) == -1)
{
fprintf(stderr, "tar_open(): %s\n", strerror(errno));
return -1;
}
#ifdef DEBUG
puts("extracting tarfile...");
#endif
if (tar_extract_all(t, rootdir) != 0)
{
fprintf(stderr, "tar_extract_all(): %s\n", strerror(errno));
return -1;
}
#ifdef DEBUG
puts("closing tarfile...");
#endif
if (tar_close(t) != 0)
{
fprintf(stderr, "tar_close(): %s\n", strerror(errno));
return -1;
}
return 0;
}
static void
usage()
{
printf("Usage: %s [-C rootdir] [-g] [-z] -x|-t filename.tar\n",
progname);
printf(" %s [-C rootdir] [-g] [-z] -c filename.tar ...\n",
progname);
exit(-1);
}
#define MODE_LIST 1
#define MODE_CREATE 2
#define MODE_EXTRACT 3
int
main(int argc, char *argv[])
{
char* tarfile;
char *rootdir = NULL;
int c;
int mode;
libtar_list_t *l;
#if defined(_WIN32) && !defined(__CYGWIN__)
int optind;
#endif
progname = basename(argv[0]);
#if !defined(_WIN32) || defined(__CYGWIN__)
mode = 0;
while ((c = getopt(argc, argv, "cC:gtvVxz")) != -1)
switch (c)
{
case 'V':
printf("libtar %s by Mark D. Roth <roth@uiuc.edu>\n",
libtar_version);
break;
case 'C':
rootdir = strdup(optarg);
break;
case 'v':
verbose = 1;
break;
case 'g':
use_gnu = 1;
break;
case 'c':
if (mode)
usage();
mode = MODE_CREATE;
break;
case 'x':
if (mode)
usage();
mode = MODE_EXTRACT;
break;
case 't':
if (mode)
usage();
mode = MODE_LIST;
break;
#ifdef HAVE_LIBZ
case 'z':
use_zlib = 1;
break;
#endif /* HAVE_LIBZ */
default:
usage();
}
if (!mode || ((argc - optind) < (mode == MODE_CREATE ? 2 : 1)))
{
#ifdef DEBUG
printf("argc - optind == %d\tmode == %d\n", argc - optind,
mode);
#endif
usage();
}
#else
mode = MODE_EXTRACT;
use_zlib=1;
optind = 1;
#endif
#ifdef DEBUG
signal(SIGSEGV, segv_handler);
#endif
switch (mode)
{
case MODE_EXTRACT:
return extract(argv[optind], rootdir);
case MODE_CREATE:
tarfile = argv[optind];
l = libtar_list_new(LIST_QUEUE, NULL);
for (c = optind + 1; c < argc; c++)
libtar_list_add(l, argv[c]);
return create(tarfile, rootdir, l);
case MODE_LIST:
return list(argv[optind]);
default:
break;
}
/* NOTREACHED */
return -2;
}