/* ** 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 ** Campus Information Technologies and Educational Services ** University of Illinois at Urbana-Champaign */ #include #include #include #include #include #if defined(_WIN32) && !defined(__CYGWIN__) #include #include #else #include #endif #ifdef STDC_HEADERS # include #endif #ifdef HAVE_UNISTD_H # include # include #endif #ifdef DEBUG # include #endif #ifdef HAVE_LIBZ # include #endif #include 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; 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(_WIN32) || defined(__CYGWIN__) if ((oflags & O_CREAT) && fchmod(fd, mode)) { return -1; } #endif gzf->GZFile = cm_zlib_gzdopen(fd, gzoflags); if (!gzf->GZFile) { errno = ENOMEM; return -1; } return fd; } int libtar_gzclose(void* call_data, int fd) { struct gzStruct* gzf = (struct gzStruct*)call_data; (void)fd; return cm_zlib_gzclose(gzf->GZFile); } ssize_t libtar_gzread(void* call_data, int fd, void* buf, size_t count) { struct gzStruct* gzf = (struct gzStruct*)call_data; (void)fd; return cm_zlib_gzread(gzf->GZFile, buf, count); } ssize_t libtar_gzwrite(void* call_data, int fd, const void* buf, size_t count) { struct gzStruct* gzf = (struct gzStruct*)call_data; (void)fd; return cm_zlib_gzwrite(gzf->GZFile, (void*)buf, count); } tartype_t gztype = { libtar_gzopen, libtar_gzclose, libtar_gzread, libtar_gzwrite, &GZStruct }; #endif /* HAVE_LIBZ */ 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; } 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; } 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; } 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 = NULL; char *rootdir = NULL; int c; int mode = 0; libtar_list_t *l; #if defined(_WIN32) && !defined(__CYGWIN__) int optind; #endif progname = basename(argv[0]); #if !defined(_WIN32) || defined(__CYGWIN__) while ((c = getopt(argc, argv, "cC:gtvVxz")) != -1) switch (c) { case 'V': printf("libtar %s by Mark D. Roth \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; }