[Cmake-commits] [cmake-commits] hoffman committed tarfilter.c NONE 1.1 untar.c NONE 1.1

cmake-commits at cmake.org cmake-commits at cmake.org
Fri Oct 30 13:09:57 EDT 2009


Update of /cvsroot/CMake/CMake/Utilities/cmlibarchive/examples
In directory public:/mounts/ram/cvs-serv26614/Utilities/cmlibarchive/examples

Added Files:
	tarfilter.c untar.c 
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: untar.c ---
/*
 * This file is in the public domain.
 * Use it as you wish.
 */

/*
 * This is a compact tar extraction program using libarchive whose
 * primary goal is small executable size.  Statically linked, it can
 * be very small, depending in large part on how cleanly factored your
 * system libraries are.  Note that this uses the standard libarchive,
 * without any special recompilation.  The only functional concession
 * is that this program uses the uid/gid from the archive instead of
 * doing uname/gname lookups.  (Add a call to
 * archive_write_disk_set_standard_lookup() to enable uname/gname
 * lookups, but be aware that this can add 500k or more to a static
 * executable, depending on the system libraries, since user/group
 * lookups frequently pull in password, YP/LDAP, networking, and DNS
 * resolver libraries.)
 *
 * To build:
 * $ gcc -static -Wall -o untar untar.c -larchive
 * $ strip untar
 *
 * NOTE: On some systems, you may need to add additional flags
 * to ensure that untar.c is compiled the same way as libarchive
 * was compiled.  In particular, Linux users will probably
 * have to add -D_FILE_OFFSET_BITS=64 to the command line above.
 *
 * For fun, statically compile the following simple hello.c program
 * using the same flags as for untar and compare the size:
 *
 * #include <stdio.h>
 * int main(int argc, char **argv) {
 *    printf("hello, world\n");
 *    return(0);
 * }
 *
 * You may be even more surprised by the compiled size of true.c listed here:
 *
 * int main(int argc, char **argv) {
 *    return (0);
 * }
 *
 * On a slightly customized FreeBSD 5 system that I used around
 * 2005, hello above compiled to 89k compared to untar of 69k.  So at
 * that time, libarchive's tar reader and extract-to-disk routines
 * compiled to less code than printf().
 *
 * On my FreeBSD development system today (August, 2009):
 *  hello: 195024 bytes
 *  true: 194912 bytes
 *  untar: 259924 bytes
 */

#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>

static void errmsg(const char *);
static void extract(const char *filename, int do_extract, int flags);
static void fail(const char *, const char *, int);
static int  copy_data(struct archive *, struct archive *);
static void msg(const char *);
static void usage(void);
static void warn(const char *, const char *);

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) {
            case 'f':
                if (*p != '\0')
                    filename = p;
                else
                    filename = *++argv;
                p += strlen(p);
                break;
            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;
            default:
                usage();
            }
        }
    }

    switch (mode) {
    case 't':
        extract(filename, 0, flags);
        break;
    case 'x':
        extract(filename, 1, flags);
        break;
    }

    return (0);
}


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);
    /*
     * Note: archive_write_disk_set_standard_lookup() is useful
     * here, but it requires library routines that can add 500k or
     * more to a static executable.
     */
    archive_read_support_format_tar(a);
    /*
     * On my system, enabling other archive formats adds 20k-30k
     * each.  Enabling gzip decompression adds about 20k.
     * Enabling bzip2 is more expensive because the libbz2 library
     * isn't very well factored.
     */
    if (filename != NULL && strcmp(filename, "-") == 0)
        filename = NULL;
    if ((r = archive_read_open_file(a, filename, 10240)))
        fail("archive_read_open_file()",
            archive_error_string(a), r);
    for (;;) {
        r = archive_read_next_header(a, &entry);
        if (r == ARCHIVE_EOF)
            break;
        if (r != ARCHIVE_OK)
            fail("archive_read_next_header()",
                archive_error_string(a), 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)
                warn("archive_write_header()",
                    archive_error_string(ext));
            else {
                copy_data(a, ext);
                r = archive_write_finish_entry(ext);
                if (r != ARCHIVE_OK)
                    fail("archive_write_finish_entry()",
                        archive_error_string(ext), 1);
            }

        }
        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)
            return (ARCHIVE_OK);
        if (r != ARCHIVE_OK)
            return (r);
        r = archive_write_data_block(aw, buff, size, offset);
        if (r != ARCHIVE_OK) {
            warn("archive_write_data_block()",
                archive_error_string(aw));
            return (r);
        }
    }
}

/*
 * These reporting functions use low-level I/O; on some systems, this
 * is a significant code reduction.  Of course, on many server and
 * desktop operating systems, malloc() and even crt rely on printf(),
 * which in turn pulls in most of the rest of stdio, so this is not an
 * optimization at all there.  (If you're going to pay 100k or more
 * for printf() anyway, you may as well use it!)
 */
static void
msg(const char *m)
{
    write(1, m, strlen(m));
}

static void
errmsg(const char *m)
{
    write(2, m, strlen(m));
}

static void
warn(const char *f, const char *m)
{
    errmsg(f);
    errmsg(" failed: ");
    errmsg(m);
    errmsg("\n");
}

static void
fail(const char *f, const char *m, int r)
{
    warn(f, m);
    exit(r);
}

static void
usage(void)
{
    const char *m = "Usage: untar [-tvx] [-f file] [file]\n";
    errmsg(m);
    exit(1);
}

--- NEW FILE: tarfilter.c ---
/*
 * This file is in the public domain.
 *
 * Feel free to use it as you wish.
 */

/*
 * This example program reads an archive from stdin (which can be in
 * any format recognized by libarchive) and writes certain entries to
 * an uncompressed ustar archive on stdout.  This is a template for
 * many kinds of archive manipulation: converting formats, resetting
 * ownership, inserting entries, removing entries, etc.
 *
 * To compile:
 * gcc -Wall -o tarfilter tarfilter.c -larchive -lz -lbz2
 */

#include <sys/stat.h>
#include <archive.h>
#include <archive_entry.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

static void
die(char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fprintf(stderr, "\n");
    exit(1);
}

int
main(int argc, char **argv)
{
    char buff[8192];
    ssize_t len;
    int r;
    mode_t m;
    struct archive *ina;
    struct archive *outa;
    struct archive_entry *entry;

    /* Read an archive from stdin, with automatic format detection. */
    ina = archive_read_new();
    if (ina == NULL)
        die("Couldn't create archive reader.");
    if (archive_read_support_compression_all(ina) != ARCHIVE_OK)
        die("Couldn't enable decompression");
    if (archive_read_support_format_all(ina) != ARCHIVE_OK)
        die("Couldn't enable read formats");
    if (archive_read_open_fd(ina, 0, 10240) != ARCHIVE_OK)
        die("Couldn't open input archive");

    /* Write an uncompressed ustar archive to stdout. */
    outa = archive_write_new();
    if (outa == NULL)
        die("Couldn't create archive writer.");
    if (archive_write_set_compression_none(outa) != ARCHIVE_OK)
        die("Couldn't enable compression");
    if (archive_write_set_format_ustar(outa) != ARCHIVE_OK)
        die("Couldn't set output format");
    if (archive_write_open_fd(outa, 1) != ARCHIVE_OK)
        die("Couldn't open output archive");

    /* Examine each entry in the input archive. */
    while ((r = archive_read_next_header(ina, &entry)) == ARCHIVE_OK) {
        fprintf(stderr, "%s: ", archive_entry_pathname(entry));

        /* Skip anything that isn't a regular file. */
        if (!S_ISREG(archive_entry_mode(entry))) {
            fprintf(stderr, "skipped\n");
            continue;
        }

        /* Make everything owned by root/wheel. */
        archive_entry_set_uid(entry, 0);
        archive_entry_set_uname(entry, "root");
        archive_entry_set_gid(entry, 0);
        archive_entry_set_gname(entry, "wheel");

        /* Make everything permission 0744, strip SUID, etc. */
        m = archive_entry_mode(entry);
        archive_entry_set_mode(entry, (m & ~07777) | 0744);

        /* Copy input entries to output archive. */
        if (archive_write_header(outa, entry) != ARCHIVE_OK)
            die("Error writing output archive");
        if (archive_entry_size(entry) > 0) {
            len = archive_read_data(ina, buff, sizeof(buff));
            while (len > 0) {
                if (archive_write_data(outa, buff, len) != len)
                    die("Error writing output archive");
                len = archive_read_data(ina, buff, sizeof(buff));
            }
            if (len < 0)
                die("Error reading input archive");
        }
        fprintf(stderr, "copied\n");
    }
    if (r != ARCHIVE_EOF)
        die("Error reading archive");
    /* Close the archives.  */
    if (archive_read_finish(ina) != ARCHIVE_OK)
        die("Error closing input archive");
    if (archive_write_finish(outa) != ARCHIVE_OK)
        die("Error closing output archive");
    return (0);
}



More information about the Cmake-commits mailing list