423 lines
7.6 KiB
C
423 lines
7.6 KiB
C
/*
|
|
** 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, 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, 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;
|
|
}
|
|
|
|
|