]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Rework minitar example to use archive_read_disk directory
authorTim Kientzle <kientzle@gmail.com>
Sun, 4 Jul 2010 02:38:06 +0000 (22:38 -0400)
committerTim Kientzle <kientzle@gmail.com>
Sun, 4 Jul 2010 02:38:06 +0000 (22:38 -0400)
traversal instead of a local copy of tree.c

SVN-Revision: 2526

examples/minitar/Makefile
examples/minitar/minitar.c
examples/minitar/tree.c [deleted file]
examples/minitar/tree.h [deleted file]

index 3cd61f36e7e0858415c7dec0abc899557ed7b852..1ec4593df66b417804097c0d5f38e9104da0d38b 100644 (file)
@@ -5,29 +5,21 @@
 #
 CFLAGS=                                \
        -DNO_BZIP2_CREATE       \
-       -DNO_BZIP2_EXTRACT      \
-       -DNO_COMPRESS_EXTRACT   \
-       -DNO_CPIO_EXTRACT       \
-       -DNO_CREATE             \
-       -DNO_GZIP_CREATE        \
-       -DNO_GZIP_EXTRACT       \
-       -DNO_LOOKUP
+       -I../../libarchive      \
+       -g
 
-# Omit 'tree.o' if you're not including create support
-#OBJS= minitar.o tree.o
-OBJS= minitar.o
+# How to link against libarchive.
+LIBARCHIVE=    ../../libarchive/libarchive.a
 
 all: minitar
 
-minitar: $(OBJS)
-       cc -o minitar -static $(OBJS) -larchive -lz -lbz2
+minitar: minitar.o
+       cc -g -o minitar minitar.o $(LIBARCHIVE) -lz -lbz2
        strip minitar
        ls -l minitar
 
 minitar.o: minitar.c
 
-tree.o: tree.c
-
 clean::
        rm -f *.o
        rm -f minitar
index 3e466ae9668e0be39d772ac62ac57f2f672f0b2e..b1575c9bedbece2b49044aa0dfb3b8bd12b9db31 100644 (file)
@@ -40,8 +40,6 @@
  */
 
 #include <sys/types.h>
-__FBSDID("$FreeBSD$");
-
 #include <sys/stat.h>
 
 #include <archive.h>
@@ -52,10 +50,6 @@ __FBSDID("$FreeBSD$");
 #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.
  */
@@ -264,28 +258,71 @@ create(const char *filename, int compress, const char **argv)
        archive_read_disk_set_standard_lookup(disk);
 #endif
        while (*argv != NULL) {
-               struct tree *t = tree_open(*argv);
-               while (tree_next(t)) {
+               struct archive *disk = archive_read_disk_new();
+               int r;
+
+               r = archive_read_disk_open(disk, *argv);
+               if (r != ARCHIVE_OK) {
+                       errmsg(archive_error_string(disk));
+                       errmsg("\n");
+                       exit(1);
+               }
+
+               for (;;) {
+                       int needcr = 0;
+
                        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));
+                       r = archive_read_next_header2(disk, entry);
+                       if (r == ARCHIVE_EOF)
+                               break;
+                       if (r != ARCHIVE_OK) {
+                               errmsg(archive_error_string(disk));
+                               errmsg("\n");
+                               exit(1);
+                       }
+                       archive_read_disk_descend(disk);
                        if (verbose) {
                                msg("a ");
-                               msg(tree_current_path(t));
+                               msg(archive_entry_pathname(entry));
+                               needcr = 1;
+                       }
+                       r = archive_write_header(a, entry);
+                       if (r < ARCHIVE_OK) {
+                               errmsg(": ");
+                               errmsg(archive_error_string(a));
+                               needcr = 1;
                        }
-                       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);
+                       if (r == ARCHIVE_FATAL)
+                               exit(1);
+                       if (r > ARCHIVE_FAILED) {
+#if 0
+                               /* Ideally, we would be able to use
+                                * the same code to copy a body from
+                                * an archive_read_disk to an
+                                * archive_write that we use for
+                                * copying data from an archive_read
+                                * to an archive_write_disk.
+                                * Unfortunately, this doesn't quite
+                                * work yet. */
+                               copy_data(disk, a);
+#else
+                               /* For now, we use a simpler loop to copy data
+                                * into the target archive. */
+                               fd = open(archive_entry_sourcepath(entry), 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);
+#endif
                        }
-                       close(fd);
                        archive_entry_free(entry);
-                       if (verbose)
+                       if (needcr)
                                msg("\n");
                }
+               archive_read_close(disk);
+               archive_read_free(disk);
                argv++;
        }
        archive_write_close(a);
diff --git a/examples/minitar/tree.c b/examples/minitar/tree.c
deleted file mode 100644 (file)
index 8af0b4d..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-/*-
- * 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
diff --git a/examples/minitar/tree.h b/examples/minitar/tree.h
deleted file mode 100644 (file)
index 554e6c2..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*-
- * 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 *);