[Cmake-commits] [cmake-commits] hoffman committed Makefile NONE 1.1 shar.1 NONE 1.1 shar.c NONE 1.1 tree.c NONE 1.1 tree.h NONE 1.1 tree_config.h NONE 1.1

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


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

Added Files:
	Makefile shar.1 shar.c tree.c tree.h tree_config.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: shar.c ---
/*-
 * Copyright (c) 2008 Jaakko Heinonen
 * 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.
 */

#include <sys/cdefs.h>
#ifdef __FBSDID
__FBSDID("$FreeBSD$");
#endif

#include <sys/stat.h>
#include <sys/types.h>

#include <archive.h>
#include <archive_entry.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>

#include "tree.h"

/* command line options */
static int  b_opt;  /* use alternative shar binary format */
static int  r_opt;  /* recurse into subdirectories */
static char *o_arg; /* output file name */

static void
usage(void)
{
    fprintf(stderr, "Usage: shar [-br] [-o filename] file ...\n");
    exit(EX_USAGE);
}

/*
 * Initialize archive structure and create a shar archive.
 */
static struct archive *
shar_create(void)
{
    struct archive *a;

    if ((a = archive_write_new()) == NULL)
        errx(EXIT_FAILURE, "%s", archive_error_string(a));

    if (b_opt)
        archive_write_set_format_shar_dump(a);
    else
        archive_write_set_format_shar(a);
    archive_write_set_compression_none(a);

    if (archive_write_open_filename(a, o_arg) != ARCHIVE_OK)
        errx(EX_CANTCREAT, "%s", archive_error_string(a));

    return (a);
}

/* buffer for file data */
static char buffer[32768];

/*
 * Write file data to an archive entry.
 */
static int
shar_write_entry_data(struct archive *a, const int fd)
{
    ssize_t bytes_read, bytes_written;

    assert(a != NULL);
    assert(fd >= 0);

    bytes_read = read(fd, buffer, sizeof(buffer));
    while (bytes_read != 0) {
        if (bytes_read < 0) {
            archive_set_error(a, errno, "Read failed");
            return (ARCHIVE_WARN);
        }
        bytes_written = archive_write_data(a, buffer, bytes_read);
        if (bytes_written < 0)
            return (ARCHIVE_WARN);
        bytes_read = read(fd, buffer, sizeof(buffer));
    }

    return (ARCHIVE_OK);
}

/*
 * Write a file to the archive. We have special handling for symbolic links.
 */
static int
shar_write_entry(struct archive *a, const char *pathname, const char *accpath,
    const struct stat *st)
{
    struct archive_entry *entry;
    int fd = -1;
    int ret = ARCHIVE_OK;

    assert(a != NULL);
    assert(pathname != NULL);
    assert(accpath != NULL);
    assert(st != NULL);

    entry = archive_entry_new();

    if (S_ISREG(st->st_mode) && st->st_size > 0) {
        /* regular file */
        if ((fd = open(accpath, O_RDONLY)) == -1) {
            warn("%s", accpath);
            ret = ARCHIVE_WARN;
            goto out;
        }
    } else if (S_ISLNK(st->st_mode)) {
        /* symbolic link */
        char lnkbuff[PATH_MAX + 1];
        int lnklen;
        if ((lnklen = readlink(accpath, lnkbuff, PATH_MAX)) == -1) {
            warn("%s", accpath);
            ret = ARCHIVE_WARN;
            goto out;
        }
        lnkbuff[lnklen] = '\0';
        archive_entry_set_symlink(entry, lnkbuff);
    }
    archive_entry_copy_stat(entry, st);
    archive_entry_set_pathname(entry, pathname);
    if (!S_ISREG(st->st_mode) || st->st_size == 0)
        archive_entry_set_size(entry, 0);
    if (archive_write_header(a, entry) != ARCHIVE_OK) {
        warnx("%s: %s", pathname, archive_error_string(a));
        ret = ARCHIVE_WARN;
        goto out;
    }
    if (fd >= 0) {
        if ((ret = shar_write_entry_data(a, fd)) != ARCHIVE_OK)
            warnx("%s: %s", accpath, archive_error_string(a));
    }
out:
    archive_entry_free(entry);
    if (fd >= 0)
        close(fd);

    return (ret);
}

/*
 * Write singe path to the archive. The path can be a regular file, directory
 * or device. Symbolic links are followed.
 */
static int
shar_write_path(struct archive *a, const char *pathname)
{
    struct stat st;

    assert(a != NULL);
    assert(pathname != NULL);

    if ((stat(pathname, &st)) == -1) {
        warn("%s", pathname);
        return (ARCHIVE_WARN);
    }

    return (shar_write_entry(a, pathname, pathname, &st));
}

/*
 * Write tree to the archive. If pathname is a symbolic link it will be
 * followed. Other symbolic links are stored as such to the archive.
 */
static int
shar_write_tree(struct archive *a, const char *pathname)
{
    struct tree *t;
    const struct stat *lst, *st;
    int error = 0;
    int tree_ret;
    int first;

    assert(a != NULL);
    assert(pathname != NULL);

    t = tree_open(pathname);
    for (first = 1; (tree_ret = tree_next(t)); first = 0) {
        if (tree_ret == TREE_ERROR_DIR) {
            warnx("%s: %s", tree_current_path(t),
                strerror(tree_errno(t)));
            error = 1;
            continue;
        } else if (tree_ret != TREE_REGULAR)
            continue;
        if ((lst = tree_current_lstat(t)) == NULL) {
            warn("%s", tree_current_path(t));
            error = 1;
            continue;
        }
        /*
         * If the symlink was given on command line then
         * follow it rather than write it as symlink.
         */
        if (first && S_ISLNK(lst->st_mode)) {
            if ((st = tree_current_stat(t)) == NULL) {
                warn("%s", tree_current_path(t));
                error = 1;
                continue;
            }
        } else
            st = lst;

        if (shar_write_entry(a, tree_current_path(t),
            tree_current_access_path(t), st) != ARCHIVE_OK)
            error = 1;

        tree_descend(t);
    }

    tree_close(t);

    return ((error != 0) ? ARCHIVE_WARN : ARCHIVE_OK);
}

/*
 * Create a shar archive and write files/trees into it.
 */
static int
shar_write(char **fn, size_t nfn)
{
    struct archive *a;
    size_t i;
    int error = 0;

    assert(fn != NULL);
    assert(nfn > 0);

    a = shar_create();

    for (i = 0; i < nfn; i++) {
        if (r_opt) {
            if (shar_write_tree(a, fn[i]) !=  ARCHIVE_OK)
                error = 1;
        } else {
            if (shar_write_path(a, fn[i]) != ARCHIVE_OK)
                error = 1;
        }
    }

    if (archive_write_finish(a) != ARCHIVE_OK)
        errx(EXIT_FAILURE, "%s", archive_error_string(a));

    if (error != 0)
        warnx("Error exit delayed from previous errors.");

    return (error);
}

int
main(int argc, char **argv)
{
    int opt;

    while ((opt = getopt(argc, argv, "bro:")) != -1) {
        switch (opt) {
        case 'b':
            b_opt = 1;
            break;
        case 'o':
            o_arg = optarg;
            break;
        case 'r':
            r_opt = 1;
            break;
        default:
            usage();
            /* NOTREACHED */
        }
    }
    argc -= optind;
    argv += optind;

    if(argc < 1)
        usage();

    if (shar_write(argv, argc) != 0)
        exit(EXIT_FAILURE);
    else
        exit(EXIT_SUCCESS);
    /* NOTREACHED */
}


--- NEW FILE: tree.c ---
/*-
 * Copyright (c) 2003-2007 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.
 * 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.
 */

/*-
 * This is a new directory-walking system that addresses a number
 * of problems I've had with fts(3).  In particular, it has no
 * pathname-length limits (other than the size of 'int'), handles
 * deep logical traversals, uses considerably less memory, and has
 * an opaque interface (easier to modify in the future).
 *
 * Internally, it keeps 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 "tree_config.h"
__FBSDID("$FreeBSD$");

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "tree.h"

/*
 * TODO:
 *    1) Loop checking.
 *    3) Arbitrary logical traversals by closing/reopening intermediate fds.
 */

struct tree_entry {
    struct tree_entry *next;
    struct tree_entry *parent;
    char *name;
    size_t dirname_length;
    dev_t dev;
    ino_t ino;
    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 needsPreVisit 4 /* This entry needs to be previsited. */
#define needsPostVisit 8 /* This entry needs to be postvisited. */

/*
 * Local data for this package.
 */
struct tree {
    struct tree_entry   *stack;
    struct tree_entry   *current;
    DIR *d;
    int  initialDirFd;
    int  flags;
    int  visit_type;
    int  tree_errno; /* Error code from last failed operation. */

    char    *buff;
    const 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. */


#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
#include <stdio.h>
void
tree_dump(struct tree *t, FILE *out)
{
    struct tree_entry *te;

    fprintf(out, "\tdepth: %d\n", t->depth);
    fprintf(out, "\tbuff: %s\n", t->buff);
    fprintf(out, "\tpwd: "); fflush(stdout); system("pwd");
    fprintf(out, "\taccess: %s\n", t->basename);
    fprintf(out, "\tstack:\n");
    for (te = t->stack; te != NULL; te = te->next) {
        fprintf(out, "\t\tte->name: %s%s%s\n", te->name,
            te->flags & needsPreVisit ? "" : " *",
            t->current == te ? " (current)" : "");
    }
}
#endif

/*
 * Add a directory path to the current stack.
 */
static void
tree_push(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 = needsPreVisit | needsPostVisit;
    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)
{
    char *p;

    if (t->buff != NULL)
        t->buff[t->dirname_length] = '\0';
    /* Strip trailing '/' from name, unless entire name is "/". */
    while (name_length > 1 && name[name_length - 1] == '/')
        name_length--;

    /* 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);
    }
    p = t->buff + t->dirname_length;
    t->path_length = t->dirname_length + name_length;
    /* Add a separating '/' if it's needed. */
    if (t->dirname_length > 0 && p[-1] != '/') {
        *p++ = '/';
        t->path_length ++;
    }
    strncpy(p, name, name_length);
    p[name_length] = '\0';
    t->basename = p;
}

/*
 * 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;

    t->buff[t->dirname_length] = '\0';
    if (t->stack == t->current && t->current != NULL)
        t->current = t->current->parent;
    te = t->stack;
    t->stack = te->next;
    t->dirname_length = te->dirname_length;
    t->basename = t->buff + t->dirname_length;
    /* Special case: starting dir doesn't skip leading '/'. */
    if (t->dirname_length > 0)
        t->basename++;
    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 (t->visit_type = TREE_REGULAR);
    }

    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 (t->visit_type = TREE_REGULAR);
            }
        }

        /* If the current dir needs to be visited, set it up. */
        if (t->stack->flags & needsPreVisit) {
            t->current = t->stack;
            tree_append(t, t->stack->name, strlen(t->stack->name));
            t->stack->flags &= ~needsPreVisit;
            /* 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;
            }
            t->dirname_length = t->path_length;
            if (chdir(t->stack->name) != 0) {
                /* chdir() failed; return error */
                tree_pop(t);
                t->tree_errno = errno;
                return (t->visit_type = TREE_ERROR_DIR);
            }
            t->depth++;
            t->d = opendir(".");
            if (t->d == NULL) {
                tree_ascend(t); /* Undo "chdir" */
                tree_pop(t);
                t->tree_errno = errno;
                return (t->visit_type = TREE_ERROR_DIR);
            }
            t->flags &= ~hasLstat;
            t->flags &= ~hasStat;
            t->basename = ".";
            return (t->visit_type = TREE_POSTDESCENT);
        }

        /* We've done everything necessary for the top stack entry. */
        if (t->stack->flags & needsPostVisit) {
            tree_ascend(t);
            tree_pop(t);
            t->flags &= ~hasLstat;
            t->flags &= ~hasStat;
            return (t->visit_type = TREE_POSTASCENT);
        }
    }
    return (t->visit_type = 0);
}

/*
 * Return error code.
 */
int
tree_errno(struct tree *t)
{
    return (t->tree_errno);
}

/*
 * Called by the client to mark the directory just returned from
 * tree_next() as needing to be visited.
 */
void
tree_descend(struct tree *t)
{
    if (t->visit_type != TREE_REGULAR)
        return;

    if (tree_current_is_physical_dir(t)) {
        tree_push(t, t->basename);
        t->stack->flags |= isDir;
    } else if (tree_current_is_dir(t)) {
        tree_push(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)) {
        if (stat(t->basename, &t->st) != 0)
            return NULL;
        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)) {
        if (lstat(t->basename, &t->lst) != 0)
            return NULL;
        t->flags |= hasLstat;
    }
    return (&t->lst);
}

/*
 * Test whether current entry is a dir or link to a dir.
 */
int
tree_current_is_dir(struct tree *t)
{
    const struct stat *st;

    /*
     * If we already have lstat() info, then try some
     * cheap tests to determine if this is a dir.
     */
    if (t->flags & hasLstat) {
        /* If lstat() says it's a dir, it must be a dir. */
        if (S_ISDIR(tree_current_lstat(t)->st_mode))
            return 1;
        /* Not a dir; might be a link to a dir. */
        /* If it's not a link, then it's not a link to a dir. */
        if (!S_ISLNK(tree_current_lstat(t)->st_mode))
            return 0;
        /*
         * It's a link, but we don't know what it's a link to,
         * so we'll have to use stat().
         */
    }

    st = tree_current_stat(t);
    /* If we can't stat it, it's not a dir. */
    if (st == NULL)
        return 0;
    /* Use the definitive test.  Hopefully this is cached. */
    return (S_ISDIR(st->st_mode));
}

/*
 * Test whether current entry is a physical directory.  Usually, we
 * already have at least one of stat() or lstat() in memory, so we
 * use tricks to try to avoid an extra trip to the disk.
 */
int
tree_current_is_physical_dir(struct tree *t)
{
    const struct stat *st;

    /*
     * If stat() says it isn't a dir, then it's not a dir.
     * If stat() data is cached, this check is free, so do it first.
     */
    if ((t->flags & hasStat)
        && (!S_ISDIR(tree_current_stat(t)->st_mode)))
        return 0;

    /*
     * Either stat() said it was a dir (in which case, we have
     * to determine whether it's really a link to a dir) or
     * stat() info wasn't available.  So we use lstat(), which
     * hopefully is already cached.
     */

    st = tree_current_lstat(t);
    /* If we can't stat it, it's not a dir. */
    if (st == NULL)
        return 0;
    /* Use the definitive test.  Hopefully this is cached. */
    return (S_ISDIR(st->st_mode));
}

/*
 * Test whether current entry is a symbolic link.
 */
int
tree_current_is_physical_link(struct tree *t)
{
    const struct stat *st = tree_current_lstat(t);
    if (st == NULL)
        return 0;
    return (S_ISLNK(st->st_mode));
}

/*
 * 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);
}

--- NEW FILE: tree.h ---
/*-
 * Copyright (c) 2003-2007 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.
 * 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.
 *
 * $FreeBSD$
 */

/*-
 * 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>
#include <stdio.h>

struct tree;

/* Initiate/terminate a tree traversal. */
struct tree *tree_open(const char * /* pathname */);
void tree_close(struct tree *);

/*
 * tree_next() returns Zero if there is no next entry, non-zero if there is.
 * Note that directories are potentially visited three times.  The first
 * time as "regular" file.  If tree_descend() is invoked at that time,
 * the directory is added to a work list and will be visited two more
 * times:  once just after descending into the directory and again
 * just after ascending back to the parent.
 *
 * TREE_ERROR is returned if the descent failed (because the
 * directory couldn't be opened, for instance).  This is returned
 * instead of TREE_PREVISIT/TREE_POSTVISIT.
 */
#define TREE_REGULAR    1
#define TREE_POSTDESCENT    2
#define TREE_POSTASCENT 3
#define TREE_ERROR_DIR  -1
int tree_next(struct tree *);

int tree_errno(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 *);

/*
 * 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, and caches the
 * results, you should take advantage of it here if you need it rather
 * than make a redundant stat() or lstat() call of your own.
 */
const struct stat *tree_current_stat(struct tree *);
const struct stat *tree_current_lstat(struct tree *);
/* The following tests may use mechanisms much faster than stat()/lstat(). */
/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */
int tree_current_is_physical_dir(struct tree *);
/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */
int tree_current_is_physical_link(struct tree *);
/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */
int tree_current_is_dir(struct tree *);

/* For testing/debugging: Dump the internal status to the given filehandle. */
void tree_dump(struct tree *, FILE *);

--- NEW FILE: Makefile ---
# $FreeBSD$

PROG=   shar
SRCS=   shar.c tree.c

WARNS?= 6

DPADD=  ${LIBARCHIVE}
LDADD=  -larchive

LINKS=  ${BINDIR}/shar
MLINKS= shar.1

.include <bsd.prog.mk>

--- NEW FILE: tree_config.h ---
/*-
 * Copyright (c) 2003-2007 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.
 * 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.
 *
 * $FreeBSD$
 */
#ifndef TREE_CONFIG_H_INCLUDED
#define TREE_CONFIG_H_INCLUDED

#if defined(PLATFORM_CONFIG_H)
/*
 * Use hand-built config.h in environments that need it.
 */
#include PLATFORM_CONFIG_H
#elif defined(HAVE_CONFIG_H)
/*
 * Most POSIX platforms use the 'configure' script to build config.h
 */
#include "../config.h"
#elif defined(__FreeBSD__)
/*
 * Built-in definitions for FreeBSD.
 */
#define HAVE_DIRENT_D_NAMLEN 1
#define HAVE_DIRENT_H 1
#define HAVE_ERRNO_H 1
#define HAVE_FCNTL_H 1
#define HAVE_LIBARCHIVE 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_UNISTD_H 1
#else
/*
 * Warn if there's no platform configuration.
 */
#error Oops: No config.h and no built-in configuration in bsdtar_platform.h.
#endif /* !HAVE_CONFIG_H */

/* No non-FreeBSD platform will have __FBSDID, so just define it here. */
#ifdef __FreeBSD__
#include <sys/cdefs.h>  /* For __FBSDID */
#else
/* Just leaving this macro replacement empty leads to a dangling semicolon. */
#define __FBSDID(a)     struct _undefined_hack
#endif

#ifdef HAVE_LIBARCHIVE
/* If we're using the platform libarchive, include system headers. */
#include <archive.h>
#include <archive_entry.h>
#else
/* Otherwise, include user headers. */
#include "archive.h"
#include "archive_entry.h"
#endif

#endif /* !TREE_CONFIG_H_INCLUDED */

--- NEW FILE: shar.1 ---
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California.  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.
.\" 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.
.\" 3. All advertising materials mentioning features or use of this software
.\"    must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\"    may be used to endorse or promote products derived from this software
.\"    without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
.\"
.\"     @(#)shar.1  8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
.Dd April 17, 2008
.Dt SHAR 1
.Os
.Sh NAME
.Nm shar
.Nd create a shell archive of files
.Sh SYNOPSIS
.Nm
.Op Fl br
.Op Fl o Ar archive-file
.Ar
.Sh DESCRIPTION
The
.Nm
command writes a
.Xr sh 1
shell script which will recreate the file hierarchy specified by the command
line operands.
.Pp
The
.Nm
command is normally used for distributing files by
.Xr ftp 1
or
.Xr mail 1 .
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl b
Use an alternative binary format.  Content of files will be uuencoded.
This option should be used to archive binary files correctly.
In this mode also file permissions will be stored to the archive.
uudecode(1) is needed to extract archives created with this option.
.It Fl o Ar archive-file
Redirect output to
.Ar archive-file .
.It Fl r
If
.Ar file
given on command line is a directory the entire subtree will be archived.
Symbolic links given on command line are followed.  Other symbolic links will
be archived as such.
.El
.Sh EXAMPLES
To create a shell archive of the program
.Xr ls 1
and mail it to Rick:
.Bd -literal -offset indent
cd ls
shar -r . \&| mail -s "ls source" rick
.Ed
.Pp
To recreate the program directory:
.Bd -literal -offset indent
mkdir ls
cd ls
\&...
<delete header lines and examine mailed archive>
\&...
sh archive
.Ed
.Sh SEE ALSO
.Xr compress 1 ,
.Xr mail 1 ,
.Xr tar 1 ,
.Xr uuencode 1 ,
.Xr uuencode 5
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.4 .
This is a re-implementation based on the libarchive(3) library.
.Sh BUGS
The
.Nm
command makes no provisions for hard links.
.Pp
Files containing magic characters or files without a newline ('\\n') as the
last character are not handled correctly with the default format.  Use the -b
option for binary files.
.Pp
It is easy to insert trojan horses into
.Nm
files.
It is strongly recommended that all shell archive files be examined
before running them through
.Xr sh 1 .
Archives produced using this implementation of
.Nm
may be easily examined with the command:
.Bd -literal -offset indent
egrep -v '^[X#]' shar.file
.Ed



More information about the Cmake-commits mailing list