[Cmake-commits] [cmake-commits] hoffman committed #notes# NONE 1.1 Makefile NONE 1.1 README NONE 1.1 minitar.c NONE 1.1 notes NONE 1.1 tree.c NONE 1.1 tree.h NONE 1.1
cmake-commits at cmake.org
cmake-commits at cmake.org
Fri Oct 30 13:10:03 EDT 2009
Update of /cvsroot/CMake/CMake/Utilities/cmlibarchive/examples/minitar
In directory public:/mounts/ram/cvs-serv26614/Utilities/cmlibarchive/examples/minitar
Added Files:
#notes# Makefile README minitar.c notes tree.c tree.h
Log Message:
Switch to using libarchive from libtar for cpack and cmake -E tar
This allows for a built in bzip and zip capability, so external tools
will not be needed for these packagers. The cmake -E tar xf should be
able to handle all compression types now as well.
--- NEW FILE: tree.c ---
/*-
* Copyright (c) 2003-2004 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* There is a single list of "tree_entry" items that represent
* filesystem objects that require further attention. Non-directories
* are not kept in memory: they are pulled from readdir(), returned to
* the client, then freed as soon as possible. Any directory entry to
* be traversed gets pushed onto the stack.
*
* There is surprisingly little information that needs to be kept for
* each item on the stack. Just the name, depth (represented here as the
* string length of the parent directory's pathname), and some markers
* indicating how to get back to the parent (via chdir("..") for a
* regular dir or via fchdir(2) for a symlink).
*/
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tree.h"
/*
* TODO:
* 1) Loop checking.
* 3) Arbitrary logical traversals by closing/reopening intermediate fds.
*/
struct tree_entry {
struct tree_entry *next;
char *name;
size_t dirname_length;
int fd;
int flags;
};
/* Definitions for tree_entry.flags bitmap. */
#define isDir 1 /* This entry is a regular directory. */
#define isDirLink 2 /* This entry is a symbolic link to a directory. */
#define needsTraversal 4 /* This entry hasn't yet been traversed. */
/*
* Local data for this package.
*/
struct tree {
struct tree_entry *stack;
DIR *d;
int initialDirFd;
int flags;
char *buff;
char *basename;
size_t buff_length;
size_t path_length;
size_t dirname_length;
int depth;
int openCount;
int maxOpenCount;
struct stat lst;
struct stat st;
};
/* Definitions for tree.flags bitmap. */
#define needsReturn 8 /* Marks first entry as not having been returned yet. */
#define hasStat 16 /* The st entry is set. */
#define hasLstat 32 /* The lst entry is set. */
#define HAVE_DIRENT_D_NAMLEN 1
#ifdef HAVE_DIRENT_D_NAMLEN
/* BSD extension; avoids need for a strlen() call. */
#define D_NAMELEN(dp) (dp)->d_namlen
#else
#define D_NAMELEN(dp) (strlen((dp)->d_name))
#endif
#if 0
static void
dumpStack(struct tree *t)
{
struct tree_entry *te;
printf("\tbuff: %s\n", t->buff);
printf("\tpwd: "); fflush(stdout); system("pwd");
printf("\tstack:\n");
for (te = t->stack; te != NULL; te = te->next) {
printf("\t\tte->name: %s %s\n", te->name, te->flags & needsTraversal ? "" : "*");
}
}
#endif
/*
* Add a directory path to the current stack.
*/
static void
tree_add(struct tree *t, const char *path)
{
struct tree_entry *te;
te = malloc(sizeof(*te));
memset(te, 0, sizeof(*te));
te->next = t->stack;
t->stack = te;
te->fd = -1;
te->name = strdup(path);
te->flags = needsTraversal;
te->dirname_length = t->dirname_length;
}
/*
* Append a name to the current path.
*/
static void
tree_append(struct tree *t, const char *name, size_t name_length)
{
if (t->buff != NULL)
t->buff[t->dirname_length] = '\0';
/* Resize pathname buffer as needed. */
while (name_length + 1 + t->dirname_length >= t->buff_length) {
t->buff_length *= 2;
if (t->buff_length < 1024)
t->buff_length = 1024;
t->buff = realloc(t->buff, t->buff_length);
}
t->basename = t->buff + t->dirname_length;
t->path_length = t->dirname_length + name_length;
if (t->dirname_length > 0) {
*t->basename++ = '/';
t->path_length ++;
}
strcpy(t->basename, name);
}
/*
* Open a directory tree for traversal.
*/
struct tree *
tree_open(const char *path)
{
struct tree *t;
t = malloc(sizeof(*t));
memset(t, 0, sizeof(*t));
tree_append(t, path, strlen(path));
t->initialDirFd = open(".", O_RDONLY);
/*
* During most of the traversal, items are set up and then
* returned immediately from tree_next(). That doesn't work
* for the very first entry, so we set a flag for this special
* case.
*/
t->flags = needsReturn;
return (t);
}
/*
* We've finished a directory; ascend back to the parent.
*/
static void
tree_ascend(struct tree *t)
{
struct tree_entry *te;
te = t->stack;
t->depth--;
if (te->flags & isDirLink) {
fchdir(te->fd);
close(te->fd);
t->openCount--;
} else {
chdir("..");
}
}
/*
* Pop the working stack.
*/
static void
tree_pop(struct tree *t)
{
struct tree_entry *te;
te = t->stack;
t->stack = te->next;
t->dirname_length = te->dirname_length;
free(te->name);
free(te);
}
/*
* Get the next item in the tree traversal.
*/
int
tree_next(struct tree *t)
{
struct dirent *de = NULL;
/* Handle the startup case by returning the initial entry. */
if (t->flags & needsReturn) {
t->flags &= ~needsReturn;
return (1);
}
while (t->stack != NULL) {
/* If there's an open dir, get the next entry from there. */
while (t->d != NULL) {
de = readdir(t->d);
if (de == NULL) {
closedir(t->d);
t->d = NULL;
} else if (de->d_name[0] == '.'
&& de->d_name[1] == '\0') {
/* Skip '.' */
} else if (de->d_name[0] == '.'
&& de->d_name[1] == '.'
&& de->d_name[2] == '\0') {
/* Skip '..' */
} else {
/*
* Append the path to the current path
* and return it.
*/
tree_append(t, de->d_name, D_NAMELEN(de));
t->flags &= ~hasLstat;
t->flags &= ~hasStat;
return (1);
}
}
/* If the current dir needs to be traversed, set it up. */
if (t->stack->flags & needsTraversal) {
tree_append(t, t->stack->name, strlen(t->stack->name));
t->stack->flags &= ~needsTraversal;
/* If it is a link, set up fd for the ascent. */
if (t->stack->flags & isDirLink) {
t->stack->fd = open(".", O_RDONLY);
t->openCount++;
if (t->openCount > t->maxOpenCount)
t->maxOpenCount = t->openCount;
}
if (chdir(t->stack->name) == 0) {
t->depth++;
t->dirname_length = t->path_length;
t->d = opendir(".");
} else
tree_pop(t);
continue;
}
/* We've done everything necessary for the top stack entry. */
tree_ascend(t);
tree_pop(t);
}
return (0);
}
/*
* Called by the client to mark the directory just returned from
* tree_next() as needing to be visited.
*/
void
tree_descend(struct tree *t)
{
const struct stat *s = tree_current_lstat(t);
if (S_ISDIR(s->st_mode)) {
tree_add(t, t->basename);
t->stack->flags |= isDir;
}
if (S_ISLNK(s->st_mode) && S_ISDIR(tree_current_stat(t)->st_mode)) {
tree_add(t, t->basename);
t->stack->flags |= isDirLink;
}
}
/*
* Get the stat() data for the entry just returned from tree_next().
*/
const struct stat *
tree_current_stat(struct tree *t)
{
if (!(t->flags & hasStat)) {
stat(t->basename, &t->st);
t->flags |= hasStat;
}
return (&t->st);
}
/*
* Get the lstat() data for the entry just returned from tree_next().
*/
const struct stat *
tree_current_lstat(struct tree *t)
{
if (!(t->flags & hasLstat)) {
lstat(t->basename, &t->lst);
t->flags |= hasLstat;
}
return (&t->lst);
}
/*
* Return the access path for the entry just returned from tree_next().
*/
const char *
tree_current_access_path(struct tree *t)
{
return (t->basename);
}
/*
* Return the full path for the entry just returned from tree_next().
*/
const char *
tree_current_path(struct tree *t)
{
return (t->buff);
}
/*
* Return the length of the path for the entry just returned from tree_next().
*/
size_t
tree_current_pathlen(struct tree *t)
{
return (t->path_length);
}
/*
* Return the nesting depth of the entry just returned from tree_next().
*/
int
tree_current_depth(struct tree *t)
{
return (t->depth);
}
/*
* Terminate the traversal and release any resources.
*/
void
tree_close(struct tree *t)
{
/* Release anything remaining in the stack. */
while (t->stack != NULL)
tree_pop(t);
if (t->buff)
free(t->buff);
/* chdir() back to where we started. */
if (t->initialDirFd >= 0) {
fchdir(t->initialDirFd);
close(t->initialDirFd);
t->initialDirFd = -1;
}
free(t);
}
#if 0
/* Main function for testing. */
#include <stdio.h>
int main(int argc, char **argv)
{
size_t max_path_len = 0;
int max_depth = 0;
system("pwd");
while (*++argv) {
struct tree *t = tree_open(*argv);
while (tree_next(t)) {
size_t path_len = tree_current_pathlen(t);
int depth = tree_current_depth(t);
if (path_len > max_path_len)
max_path_len = path_len;
if (depth > max_depth)
max_depth = depth;
printf("%s\n", tree_current_path(t));
if (S_ISDIR(tree_current_lstat(t)->st_mode))
tree_descend(t); /* Descend into every dir. */
}
tree_close(t);
printf("Max path length: %d\n", max_path_len);
printf("Max depth: %d\n", max_depth);
printf("Final open count: %d\n", t->openCount);
printf("Max open count: %d\n", t->maxOpenCount);
fflush(stdout);
system("pwd");
}
return (0);
}
#endif
--- NEW FILE: tree.h ---
/*-
* Copyright (c) 2003-2004 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* A set of routines for traversing directory trees.
* Similar in concept to the fts library, but with a few
* important differences:
* * Uses less memory. In particular, fts stores an entire directory
* in memory at a time. This package only keeps enough subdirectory
* information in memory to track the traversal. Information
* about non-directories is discarded as soon as possible.
* * Supports very deep logical traversals. The fts package
* uses "non-chdir" approach for logical traversals. This
* package does use a chdir approach for logical traversals
* and can therefore handle pathnames much longer than
* PATH_MAX.
* * Supports deep physical traversals "out of the box."
* Due to the memory optimizations above, there's no need to
* limit dir names to 32k.
*/
#include <sys/stat.h>
struct tree;
struct tree *tree_open(const char *);
/* Returns TRUE if there is a next entry. Zero if there is no next entry. */
int tree_next(struct tree *);
/* Return information about the current entry. */
int tree_current_depth(struct tree *);
/*
* The current full pathname, length of the full pathname,
* and a name that can be used to access the file.
* Because tree does use chdir extensively, the access path is
* almost never the same as the full current path.
*/
const char *tree_current_path(struct tree *);
size_t tree_current_pathlen(struct tree *);
const char *tree_current_access_path(struct tree *);
/*
* Request the lstat() or stat() data for the current path.
* Since the tree package needs to do some of this anyway,
* you should take advantage of it here if you need it.
*/
const struct stat *tree_current_stat(struct tree *);
const struct stat *tree_current_lstat(struct tree *);
/*
* Request that current entry be visited. If you invoke it on every
* directory, you'll get a physical traversal. This is ignored if the
* current entry isn't a directory or a link to a directory. So, if
* you invoke this on every returned path, you'll get a full logical
* traversal.
*/
void tree_descend(struct tree *);
void tree_close(struct tree *);
--- NEW FILE: notes ---
create(const char* filename)
{
struct archive *a;
a = archive_write_new();
// pick a compression type
archive_write_set_compression_bzip2(a);
archive_write_set_compression_compress(a);
archive_write_set_compression_gzip(a);
archive_write_set_compression_none(a);
// what does this do???
archive_write_set_format_ustar(a); // is this what we want?
// maybe this:
archive_write_set_format_pax(a);
archive_write_open_file(a, filename);
struct archive* disk = archive_read_disk_new();
archive_read_disk_set_standard_lookup(disk);
while (*argv != NULL)
{
struct tree *t = tree_open(*argv);
while (tree_next(t))
{
entry = archive_entry_new();
archive_entry_set_pathname(entry, tree_current_path(t));
archive_read_disk_entry_from_file(disk, entry, -1,
tree_current_stat(t));
if (verbose)
{
msg("a ");
msg(tree_current_path(t));
}
archive_write_header(a, entry);
int fd = open(tree_current_access_path(t), O_RDONLY);
char buff[16384];
len = read(fd, buff, sizeof(buff));
while (len > 0)
{
archive_write_data(a, buff, len);
len = read(fd, buff, sizeof(buff));
}
close(fd);
archive_entry_free(entry);
if (verbose)
msg("\n");
}
}
}
--- NEW FILE: Makefile ---
#
# Adjust the following to control which options minitar gets
# built with. See comments in minitar.c for details.
#
CFLAGS= \
-DNO_BZIP2_CREATE \
-DNO_BZIP2_EXTRACT \
-DNO_COMPRESS_EXTRACT \
-DNO_CPIO_EXTRACT \
-DNO_CREATE \
-DNO_GZIP_CREATE \
-DNO_GZIP_EXTRACT \
-DNO_LOOKUP
# Omit 'tree.o' if you're not including create support
#OBJS= minitar.o tree.o
OBJS= minitar.o
all: minitar
minitar: $(OBJS)
cc -o minitar -static $(OBJS) -larchive -lz -lbz2
strip minitar
ls -l minitar
minitar.o: minitar.c
tree.o: tree.c
clean::
rm -f *.o
rm -f minitar
rm -f *~
--- NEW FILE: #notes# ---
create(const char* filename)
{
struct archive *a;
a = archive_write_new();
// pick a compression type
archive_write_set_compression_bzip2(a);
archive_write_set_compression_compress(a);
archive_write_set_compression_gzip(a);
archive_write_set_compression_none(a);
// what does this do???
archive_write_set_format_ustar(a); // is this what we want?
// maybe this:
archive_write_set_format_pax(a);
archive_write_open_file(a, filename);
struct archive* disk = archive_read_disk_new();
archive_read_disk_set_standard_lookup(disk);
while (*argv != NULL)
{
struct tree *t = tree_open(*argv);
while (tree_next(t))
{
entry = archive_entry_new();
archive_entry_set_pathname(entry, tree_current_path(t));
struct stat s;
stat(fname, &s);
archive_read_disk_entry_from_file(disk, entry, -1, &s);
if (verbose)
{
msg("a ");
msg(tree_current_path(t));
}
archive_write_header(a, entry);
int fd = open(tree_current_access_path(t), O_RDONLY);
char buff[16384];
len = read(fd, buff, sizeof(buff));
while (len > 0)
{
archive_write_data(a, buff, len);
len = read(fd, buff, sizeof(buff));
}
close(fd);
archive_entry_free(entry);
if (verbose)
msg("\n");
}
}
}
--- NEW FILE: minitar.c ---
/*-
* This file is in the public domain.
* Do with it as you will.
*/
/*-
* This is a compact "tar" program whose primary goal is small size.
* Statically linked, it can be very small indeed. This serves a number
* of goals:
* o a testbed for libarchive (to check for link pollution),
* o a useful tool for space-constrained systems (boot floppies, etc),
* o a place to experiment with new implementation ideas for bsdtar,
* o a small program to demonstrate libarchive usage.
*
* Use the following macros to suppress features:
* NO_BZIP2 - Implies NO_BZIP2_CREATE and NO_BZIP2_EXTRACT
* NO_BZIP2_CREATE - Suppress bzip2 compression support.
* NO_BZIP2_EXTRACT - Suppress bzip2 auto-detection and decompression.
* NO_COMPRESS - Implies NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT
* NO_COMPRESS_CREATE - Suppress compress(1) compression support
* NO_COMPRESS_EXTRACT - Suppress compress(1) auto-detect and decompression.
* NO_CREATE - Suppress all archive creation support.
* NO_CPIO_EXTRACT - Suppress auto-detect and dearchiving of cpio archives.
* NO_GZIP - Implies NO_GZIP_CREATE and NO_GZIP_EXTRACT
* NO_GZIP_CREATE - Suppress gzip compression support.
* NO_GZIP_EXTRACT - Suppress gzip auto-detection and decompression.
* NO_LOOKUP - Try to avoid getpw/getgr routines, which can be very large
* NO_TAR_EXTRACT - Suppress tar extraction
*
* With all of the above macros defined (except NO_TAR_EXTRACT), you
* get a very small program that can recognize and extract essentially
* any uncompressed tar archive. On FreeBSD 5.1, this minimal program
* is under 64k, statically linked, which compares rather favorably to
* main(){printf("hello, world");}
* which is over 60k statically linked on the same operating system.
* Without any of the above macros, you get a static executable of
* about 180k with a lot of very sophisticated modern features.
* Obviously, it's trivial to add support for ISO, Zip, mtree,
* lzma/xz, etc. Just fill in the appropriate setup calls.
*/
#include <sys/types.h>
__FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <archive.h>
#include <archive_entry.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef NO_CREATE
#include "tree.h"
#endif
/*
* NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE.
*/
#ifdef NO_CREATE
#undef NO_BZIP2_CREATE
#define NO_BZIP2_CREATE
#undef NO_COMPRESS_CREATE
#define NO_COMPRESS_CREATE
#undef NO_GZIP_CREATE
#define NO_GZIP_CREATE
#endif
/*
* The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is
* equivalent to NO_BZIP2.
*/
#ifdef NO_BZIP2_CREATE
#ifdef NO_BZIP2_EXTRACT
#undef NO_BZIP2
#define NO_BZIP2
#endif
#endif
#ifdef NO_BZIP2
#undef NO_BZIP2_EXTRACT
#define NO_BZIP2_EXTRACT
#undef NO_BZIP2_CREATE
#define NO_BZIP2_CREATE
#endif
/*
* The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is
* equivalent to NO_COMPRESS.
*/
#ifdef NO_COMPRESS_CREATE
#ifdef NO_COMPRESS_EXTRACT
#undef NO_COMPRESS
#define NO_COMPRESS
#endif
#endif
#ifdef NO_COMPRESS
#undef NO_COMPRESS_EXTRACT
#define NO_COMPRESS_EXTRACT
#undef NO_COMPRESS_CREATE
#define NO_COMPRESS_CREATE
#endif
/*
* The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is
* equivalent to NO_GZIP.
*/
#ifdef NO_GZIP_CREATE
#ifdef NO_GZIP_EXTRACT
#undef NO_GZIP
#define NO_GZIP
#endif
#endif
#ifdef NO_GZIP
#undef NO_GZIP_EXTRACT
#define NO_GZIP_EXTRACT
#undef NO_GZIP_CREATE
#define NO_GZIP_CREATE
#endif
#ifndef NO_CREATE
static void create(const char *filename, int compress, const char **argv);
#endif
static void errmsg(const char *);
static void extract(const char *filename, int do_extract, int flags);
static int copy_data(struct archive *, struct archive *);
static void msg(const char *);
static void usage(void);
static int verbose = 0;
int
main(int argc, const char **argv)
{
const char *filename = NULL;
int compress, flags, mode, opt;
(void)argc;
mode = 'x';
verbose = 0;
compress = '\0';
flags = ARCHIVE_EXTRACT_TIME;
/* Among other sins, getopt(3) pulls in printf(3). */
while (*++argv != NULL && **argv == '-') {
const char *p = *argv + 1;
while ((opt = *p++) != '\0') {
switch (opt) {
#ifndef NO_CREATE
case 'c':
mode = opt;
break;
#endif
case 'f':
if (*p != '\0')
filename = p;
else
filename = *++argv;
p += strlen(p);
break;
#ifndef NO_BZIP2_CREATE
case 'j':
compress = opt;
break;
#endif
case 'p':
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
break;
case 't':
mode = opt;
break;
case 'v':
verbose++;
break;
case 'x':
mode = opt;
break;
#ifndef NO_BZIP2_CREATE
case 'y':
compress = opt;
break;
#endif
#ifndef NO_COMPRESS_CREATE
case 'Z':
compress = opt;
break;
#endif
#ifndef NO_GZIP_CREATE
case 'z':
compress = opt;
break;
#endif
default:
usage();
}
}
}
switch (mode) {
#ifndef NO_CREATE
case 'c':
create(filename, compress, argv);
break;
#endif
case 't':
extract(filename, 0, flags);
break;
case 'x':
extract(filename, 1, flags);
break;
}
return (0);
}
#ifndef NO_CREATE
static char buff[16384];
static void
create(const char *filename, int compress, const char **argv)
{
struct archive *a;
struct archive *disk;
struct archive_entry *entry;
ssize_t len;
int fd;
a = archive_write_new();
switch (compress) {
#ifndef NO_BZIP2_CREATE
case 'j': case 'y':
archive_write_set_compression_bzip2(a);
break;
#endif
#ifndef NO_COMPRESS_CREATE
case 'Z':
archive_write_set_compression_compress(a);
break;
#endif
#ifndef NO_GZIP_CREATE
case 'z':
archive_write_set_compression_gzip(a);
break;
#endif
default:
archive_write_set_compression_none(a);
break;
}
archive_write_set_format_ustar(a);
if (strcmp(filename, "-") == 0)
filename = NULL;
archive_write_open_file(a, filename);
disk = archive_read_disk_new();
#ifndef NO_LOOKUP
archive_read_disk_set_standard_lookup(disk);
#endif
while (*argv != NULL) {
struct tree *t = tree_open(*argv);
while (tree_next(t)) {
entry = archive_entry_new();
archive_entry_set_pathname(entry, tree_current_path(t));
archive_read_disk_entry_from_file(disk, entry, -1,
tree_current_stat(t));
if (verbose) {
msg("a ");
msg(tree_current_path(t));
}
archive_write_header(a, entry);
fd = open(tree_current_access_path(t), O_RDONLY);
len = read(fd, buff, sizeof(buff));
while (len > 0) {
archive_write_data(a, buff, len);
len = read(fd, buff, sizeof(buff));
}
close(fd);
archive_entry_free(entry);
if (verbose)
msg("\n");
}
argv++;
}
archive_write_close(a);
archive_write_finish(a);
}
#endif
static void
extract(const char *filename, int do_extract, int flags)
{
struct archive *a;
struct archive *ext;
struct archive_entry *entry;
int r;
a = archive_read_new();
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
#ifndef NO_BZIP2_EXTRACT
archive_read_support_compression_bzip2(a);
#endif
#ifndef NO_GZIP_EXTRACT
archive_read_support_compression_gzip(a);
#endif
#ifndef NO_COMPRESS_EXTRACT
archive_read_support_compression_compress(a);
#endif
#ifndef NO_TAR_EXTRACT
archive_read_support_format_tar(a);
#endif
#ifndef NO_CPIO_EXTRACT
archive_read_support_format_cpio(a);
#endif
#ifndef NO_LOOKUP
archive_write_disk_set_standard_lookup(ext);
#endif
if (filename != NULL && strcmp(filename, "-") == 0)
filename = NULL;
if ((r = archive_read_open_file(a, filename, 10240))) {
errmsg(archive_error_string(a));
errmsg("\n");
exit(r);
}
for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF)
break;
if (r != ARCHIVE_OK) {
errmsg(archive_error_string(a));
errmsg("\n");
exit(1);
}
if (verbose && do_extract)
msg("x ");
if (verbose || !do_extract)
msg(archive_entry_pathname(entry));
if (do_extract) {
r = archive_write_header(ext, entry);
if (r != ARCHIVE_OK)
errmsg(archive_error_string(a));
else
copy_data(a, ext);
}
if (verbose || !do_extract)
msg("\n");
}
archive_read_close(a);
archive_read_finish(a);
exit(0);
}
static int
copy_data(struct archive *ar, struct archive *aw)
{
int r;
const void *buff;
size_t size;
off_t offset;
for (;;) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF) {
errmsg(archive_error_string(ar));
return (ARCHIVE_OK);
}
if (r != ARCHIVE_OK)
return (r);
r = archive_write_data_block(aw, buff, size, offset);
if (r != ARCHIVE_OK) {
errmsg(archive_error_string(ar));
return (r);
}
}
}
static void
msg(const char *m)
{
write(1, m, strlen(m));
}
static void
errmsg(const char *m)
{
write(2, m, strlen(m));
}
static void
usage(void)
{
/* Many program options depend on compile options. */
const char *m = "Usage: minitar [-"
#ifndef NO_CREATE
"c"
#endif
#ifndef NO_BZIP2
"j"
#endif
"tvx"
#ifndef NO_BZIP2
"y"
#endif
#ifndef NO_COMPRESS
"Z"
#endif
#ifndef NO_GZIP
"z"
#endif
"] [-f file] [file]\n";
errmsg(m);
exit(1);
}
--- NEW FILE: README ---
"minitar" is a minimal example of a program that uses libarchive to
read/write various archive formats. It's a more ambitious version of
'untar.c' that includes compile-time options to enable/disable various
features, including non-tar formats, archive creation, and automatic
decompression support.
I use this as a test bed to check for "link pollution," ensuring that
a program using libarchive does not pull in unnecessary code.
The "minitar" program is also a good starting point for anyone who
wants to use libarchive for their own purposes, as it demonstrates
basic usage of the library.
More information about the Cmake-commits
mailing list